AllowAll api policy added 36/85436/5
authorpkaras <piotr.karas@nokia.com>
Tue, 16 Apr 2019 10:02:17 +0000 (12:02 +0200)
committerpkaras <piotr.karas@nokia.com>
Tue, 16 Apr 2019 11:53:03 +0000 (13:53 +0200)
Change-Id: I1673b5647b0917ca18fe9b814d876a07d881021a
Issue-ID: DMAAP-1166
Signed-off-by: piotr.karas <piotr.karas@nokia.com>
13 files changed:
etc/dmaapbc.properties
src/main/java/org/onap/dmaap/dbcapi/authentication/AafLurAndFish.java
src/main/java/org/onap/dmaap/dbcapi/authentication/AllowAll.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/authentication/ApiPolicy.java
src/main/java/org/onap/dmaap/dbcapi/authentication/AuthenticationErrorException.java
src/main/java/org/onap/dmaap/dbcapi/server/Main.java
src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java
src/main/java/org/onap/dmaap/dbcapi/service/Credentials.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/CredentialsParser.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DmaapService.java
src/test/java/org/onap/dmaap/dbcapi/authentication/AllowAllTest.java [new file with mode: 0644]
src/test/java/org/onap/dmaap/dbcapi/authentication/ApiPolicyTest.java [new file with mode: 0644]
src/test/java/org/onap/dmaap/dbcapi/service/CredentialsParserTest.java [new file with mode: 0644]

index b0dc7de..71f0b66 100644 (file)
@@ -174,7 +174,7 @@ CredentialCodecKeyfile:     etc/LocalKey
 #
 # This overrides the Class used for API Permission check.
 # This allows for a plugin policy check, if needed
-#ApiPermission.Class: com.company.policy.DecisionPolicy
+ApiPermission.Class: org.onap.dmaap.dbcapi.authentication.AllowAll
 
 #
 # URL of AAF environment to use.
index 9defe34..d286df2 100644 (file)
@@ -8,9 +8,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 package org.onap.dmaap.dbcapi.authentication;
 
 
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Properties;
-
 import org.apache.log4j.Logger;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.LocatorException;
@@ -34,17 +30,21 @@ import org.onap.dmaap.dbcapi.aaf.AafLurService;
 import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
 import org.onap.dmaap.dbcapi.util.DmaapConfig;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+
 
-       
 
 public class AafLurAndFish implements ApiAuthorizationCheckInterface {
        private AafLurService svc;
        private static String apiNamespace;
        private static final String ERROR="Error";
        static final Logger logger = Logger.getLogger(AafLurAndFish.class);
-       
+
        AafLurAndFish()  throws AuthenticationErrorException  {
-       
+
                DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
                apiNamespace = p.getProperty( "ApiNamespace", "org.onap.dmaap-bc.api");
 
@@ -65,36 +65,38 @@ public class AafLurAndFish implements ApiAuthorizationCheckInterface {
                }
                try {
                        PropAccess myAccess = new PropAccess( props );
-               
+
                        svc =  AafLurService.getInstance(myAccess);
                } catch (APIException | CadiException | LocatorException e ) {
                        logger.error(ERROR, e);
                        logger.error( e.toString() );
                        throw new AuthenticationErrorException();
                }
-       
+
        }
-       
+
        public void check( String mechid, String pwd, DmaapPerm p ) throws AuthenticationErrorException {
-       
+
                try {
-                       boolean resp = svc.checkPerm( apiNamespace, mechid, pwd, p );
-                       boolean flag = false;
-                       if ( resp == flag ) {
+                   if (mechid.isEmpty() || pwd.isEmpty()) {
+                throw new AuthenticationErrorException("No basic authorization value provided");
+            }
+
+                       if (!svc.checkPerm( apiNamespace, mechid, pwd, p )) {
                                throw new AuthenticationErrorException();
                        }
-               } catch ( IOException | CadiException  e ) { 
+               } catch ( IOException | CadiException  e ) {
                        logger.error(ERROR, e);
                        logger.error( e.toString() );
                        throw new AuthenticationErrorException();
                }
-               
+
        }
-       
+
         public static void main(String[] args) throws Exception {
                AafLurAndFish alaf = new AafLurAndFish();
                DmaapPerm p = new DmaapPerm( "org.onap.dmaap-bc.api.dmaap", "boot", "GET");
-               
+
                try {
                        alaf.check("mmanager@people.osaaf.org", "demo123456!", p);
                } catch (AuthenticationErrorException aee ) {
diff --git a/src/main/java/org/onap/dmaap/dbcapi/authentication/AllowAll.java b/src/main/java/org/onap/dmaap/dbcapi/authentication/AllowAll.java
new file mode 100644 (file)
index 0000000..2e83e6c
--- /dev/null
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.authentication;
+
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+
+public class AllowAll implements ApiAuthorizationCheckInterface {
+    @Override
+    public void check(String mechid, String pwd, DmaapPerm p) {
+    }
+}
index 6aa2d88..16d0367 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,42 +24,40 @@ import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
 import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
 import org.onap.dmaap.dbcapi.util.DmaapConfig;
 
+import java.util.Properties;
+
 public class ApiPolicy extends BaseLoggingClass {
-       static String allow = "allow";
-       String dClass = null;
-       private boolean useAuthClass;
-       ApiAuthorizationCheckInterface perm = null;
-       
-       public ApiPolicy() {
-               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
-               dClass = p.getProperty( "ApiPermission.Class", allow );
-               logger.info( "ApiPolicy implements " + dClass);
-               if ( dClass.equalsIgnoreCase( allow )) {
-                       useAuthClass = false;
-                       return;
-               }               
-               useAuthClass = true;
-               logger.info( "dClass=" + dClass + " useAuthClass=" + useAuthClass );
-               try {
-                       perm = (ApiAuthorizationCheckInterface) (Class.forName(dClass).newInstance());  
-               } catch (Exception ee ) {
-                       errorLogger.error(DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, "attempting to instantiate " + dClass  );         
-                       errorLogger.error( "trace is: " + ee );
-               }       
-       }
-       
-       public void check( String mechid, String pwd, DmaapPerm p ) throws AuthenticationErrorException {
-               if ( dClass.equalsIgnoreCase( allow )) {
-                       return;
-               }
-               
-               // execute check of loaded class
-               perm.check( mechid, pwd, p );
-       
-       }
-       
-       public boolean getUseAuthClass() {
-               return useAuthClass;
-       }
 
+    private boolean permissionClassSet = true;
+    private ApiAuthorizationCheckInterface perm = null;
+
+    public ApiPolicy() {
+        this(DmaapConfig.getConfig());
+    }
+
+    ApiPolicy(Properties p) {
+        String dClass = p.getProperty("ApiPermission.Class");
+        logger.info("ApiPolicy implements " + dClass);
+        logger.info("dClass=" + dClass + " permissionClassSet=" + permissionClassSet);
+
+        try {
+            perm = (ApiAuthorizationCheckInterface) (Class.forName(dClass).newInstance());
+        } catch (Exception ee) {
+            errorLogger.error(DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, "attempting to instantiate " + dClass);
+            errorLogger.error("trace is: " + ee);
+            permissionClassSet = false;
+        }
+    }
+
+    public void check(String mechid, String pwd, DmaapPerm p) throws AuthenticationErrorException {
+        perm.check(mechid, pwd, p);
+    }
+
+    public boolean isPermissionClassSet() {
+        return permissionClassSet;
+    }
+
+    ApiAuthorizationCheckInterface getPerm() {
+        return perm;
+    }
 }
index 5119c76..01200f7 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,8 +22,14 @@ package org.onap.dmaap.dbcapi.authentication;
 
 public class AuthenticationErrorException extends Exception {
        /**
-        * 
+        *
         */
        private static final long serialVersionUID = 1L;
 
+    public AuthenticationErrorException() {
+    }
+
+    public AuthenticationErrorException(String s) {
+        super(s);
+    }
 }
index 906337a..785f4cf 100644 (file)
@@ -99,7 +99,7 @@ public class Main extends BaseLoggingClass {
                Singleton<Dmaap> dmaapholder = DatabaseClass.getDmaap();
                String name = dmaapholder.get().getDmaapName();
                ApiPolicy apiPolicy = new ApiPolicy();
-               if ( apiPolicy.getUseAuthClass() && (name == null || name.isEmpty())) {
+               if ( apiPolicy.isPermissionClassSet() && (name == null || name.isEmpty())) {
                        ApiPerms p = new ApiPerms();
                        p.setBootMap();
                }
index e1beb28..ef1e6f4 100644 (file)
 package org.onap.dmaap.dbcapi.service;
 
 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
-import static com.att.eelf.configuration.Configuration.MDC_PARTNER_NAME;
 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
 
-import javax.xml.bind.DatatypeConverter;
 import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
 import org.onap.dmaap.dbcapi.authentication.ApiPolicy;
 import org.onap.dmaap.dbcapi.authentication.AuthenticationErrorException;
@@ -45,6 +43,7 @@ public class ApiService extends BaseLoggingClass {
     private String requestId;
     private ApiError err;
     private ApiPolicy apiPolicy;
+    private CredentialsParser credentialsParser = new CredentialsParser();
 
     public ApiService() {
 
@@ -127,29 +126,17 @@ public class ApiService extends BaseLoggingClass {
         if (env == null || env.isEmpty()) {
             env = "boot";
         }
-        if (!apiPolicy.getUseAuthClass()) {
+        if (!apiPolicy.isPermissionClassSet()) {
             return;  // skip authorization if not enabled
         }
-        if (authorization == null || authorization.isEmpty()) {
-            String errmsg = "No basic authorization value provided ";
-            err.setMessage(errmsg);
-            logger.info(errmsg);
-            throw new AuthenticationErrorException();
-        }
-        String credentials = authorization.substring("Basic".length()).trim();
-        byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
-        String decodedString = new String(decoded);
-        String[] actualCredentials = decodedString.split(":");
-        String ID = actualCredentials[0];
-        String Password = actualCredentials[1];
-        MDC.put(MDC_PARTNER_NAME, ID);
-        try {
 
+        Credentials credentials = credentialsParser.parse(authorization);
+        try {
             DmaapPerm p = new DmaapPerm(apiNamespace + "." + uri, env, method);
-            apiPolicy.check(ID, Password, p);
+            apiPolicy.check(credentials.getId(), credentials.getPwd(), p);
         } catch (AuthenticationErrorException ae) {
             String errmsg =
-                "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env
+                "User " + credentials.getId() + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env
                     + " " + method;
             logger.info(errmsg);
             err.setMessage(errmsg);
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/Credentials.java b/src/main/java/org/onap/dmaap/dbcapi/service/Credentials.java
new file mode 100644 (file)
index 0000000..aee9b4f
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+public class Credentials {
+
+    private final String id;
+    private final String pwd;
+
+    Credentials(String id, String pwd) {
+        this.id = id;
+        this.pwd = pwd;
+    }
+
+    static Credentials empty() {
+        return new Credentials("", "");
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getPwd() {
+        return pwd;
+    }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/CredentialsParser.java b/src/main/java/org/onap/dmaap/dbcapi/service/CredentialsParser.java
new file mode 100644 (file)
index 0000000..4156d1b
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import javax.xml.bind.DatatypeConverter;
+
+class CredentialsParser {
+
+    Credentials parse(String authorizationHeader) {
+        if (authorizationHeader == null || authorizationHeader.isEmpty()) {
+            return Credentials.empty();
+        }
+
+        String credentials = authorizationHeader.substring("Basic".length()).trim();
+        byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
+        String decodedString = new String(decoded);
+        String[] actualCredentials = decodedString.split(":");
+        return new Credentials(actualCredentials[0], actualCredentials[1]);
+    }
+
+}
index 408d000..3ea44cc 100644 (file)
@@ -87,7 +87,7 @@ public class DmaapService  extends BaseLoggingClass  {
                        
                        AafService aaf = new AafService( ServiceType.AAF_Admin);
                        ApiPolicy apiPolicy = new ApiPolicy();
-                       if ( apiPolicy.getUseAuthClass() ) {
+                       if ( apiPolicy.isPermissionClassSet() ) {
                                ApiPerms p = new ApiPerms();
                                p.setEnvMap();
                        }
@@ -130,7 +130,7 @@ public class DmaapService  extends BaseLoggingClass  {
                        dmaapholder.update(nd);  //need to set this so the following perms will pick up any new vals.
                        //dcaeTopicNs = dmaapholder.get().getTopicNsRoot();
                        ApiPolicy apiPolicy = new ApiPolicy();
-                       if ( apiPolicy.getUseAuthClass()) {
+                       if ( apiPolicy.isPermissionClassSet()) {
                                ApiPerms p = new ApiPerms();
                                p.setEnvMap();
                        }
diff --git a/src/test/java/org/onap/dmaap/dbcapi/authentication/AllowAllTest.java b/src/test/java/org/onap/dmaap/dbcapi/authentication/AllowAllTest.java
new file mode 100644 (file)
index 0000000..9b6ee01
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.authentication;
+
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+public class AllowAllTest {
+
+    private AllowAll allowAll = new AllowAll();
+
+    @Test
+    public void check_shouldPassValidationForAllPerms() {
+        try {
+            allowAll.check(null, null, null);
+        } catch (Exception e) {
+            fail("No exception should be thrown");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/onap/dmaap/dbcapi/authentication/ApiPolicyTest.java b/src/test/java/org/onap/dmaap/dbcapi/authentication/ApiPolicyTest.java
new file mode 100644 (file)
index 0000000..7b9fbb3
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.authentication;
+
+import org.junit.Test;
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ApiPolicyTest {
+
+    private Properties properties = new Properties();
+    private ApiPolicy apiPolicy;
+
+    @Test
+    public void check_shouldExecuteAuthorizationApi() throws Exception {
+        properties.put("ApiPermission.Class", "org.onap.dmaap.dbcapi.authentication.ApiPolicyTest$DummyApiAuthorization");
+        apiPolicy = new ApiPolicy(properties);
+
+        apiPolicy.check("mechId", "pwd", new DmaapPerm("api.perm", "*", "GET"));
+
+        assertTrue(((DummyApiAuthorization) apiPolicy.getPerm()).isCheckExecuted());
+    }
+
+    @Test
+    public void isPermissionClassSet_shouldReturnTrueForValidApiPermClass() {
+        properties.put("ApiPermission.Class", "org.onap.dmaap.dbcapi.authentication.ApiPolicyTest$DummyApiAuthorization");
+        apiPolicy = new ApiPolicy(properties);
+
+        assertTrue(apiPolicy.isPermissionClassSet());
+    }
+
+    @Test
+    public void isPermissionClassSet_shouldReturnFalseWhenPropertyIsNotSet() {
+        apiPolicy = new ApiPolicy(properties);
+
+        assertFalse(apiPolicy.isPermissionClassSet());
+    }
+
+    @Test
+    public void isPermissionClassSet_shouldReturnFalseWhenWrongClassIsSet() {
+        properties.put("ApiPermission.Class", "org.onap.dmaap.dbcapi.authentication.NotExisting");
+        apiPolicy = new ApiPolicy(properties);
+
+        assertFalse(apiPolicy.isPermissionClassSet());
+    }
+
+    public static class DummyApiAuthorization implements ApiAuthorizationCheckInterface {
+
+        private boolean checkExecuted = false;
+
+        @Override
+        public void check(String mechid, String pwd, DmaapPerm p) {
+            checkExecuted = true;
+        }
+
+        boolean isCheckExecuted() {
+            return checkExecuted;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/onap/dmaap/dbcapi/service/CredentialsParserTest.java b/src/test/java/org/onap/dmaap/dbcapi/service/CredentialsParserTest.java
new file mode 100644 (file)
index 0000000..ae5becc
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CredentialsParserTest {
+
+    private CredentialsParser credentialsParser = new CredentialsParser();
+
+    @Test
+    public void parse_shouldReturnEmptyCredentialsWhenAuthorizationHeaderIsNull() {
+
+        Credentials credentials = credentialsParser.parse(null);
+
+        assertTrue(credentials.getId().isEmpty());
+        assertTrue(credentials.getPwd().isEmpty());
+    }
+
+    @Test
+    public void parse_shouldReturnEmptyCredentialsWhenAuthorizationHeaderIsEmpty() {
+
+        Credentials credentials = credentialsParser.parse("");
+
+        assertTrue(credentials.getId().isEmpty());
+        assertTrue(credentials.getPwd().isEmpty());
+    }
+
+    @Test
+    public void parse_shouldParseCorrectCredentials() {
+
+        Credentials credentials = credentialsParser.parse("Basic dXNlcjpwYXNzd29yZA==");
+
+        assertEquals("user", credentials.getId());
+        assertEquals("password", credentials.getPwd());
+    }
+}
\ No newline at end of file