diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
index 1339cc580ee..045e916fcfd 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
@@ -253,6 +253,11 @@
powermock-api-mockito
test
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.identity.jwt.client.extension
+ test
+
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticator.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticator.java
index 99fd36d5342..7f9a8bb54c4 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticator.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticator.java
@@ -86,6 +86,12 @@ public class JWTAuthenticator implements WebappAuthenticator {
@Override
public AuthenticationInfo authenticate(Request request, Response response) {
String requestUri = request.getRequestURI();
+ SignedJWT jwsObject;
+ String username;
+ String tenantDomain;
+ int tenantId;
+ String issuer;
+
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
if (requestUri == null || "".equals(requestUri)) {
authenticationInfo.setStatus(Status.CONTINUE);
@@ -101,12 +107,17 @@ public class JWTAuthenticator implements WebappAuthenticator {
try {
String authorizationHeader = request.getHeader(JWT_ASSERTION_HEADER);
+ jwsObject = SignedJWT.parse(authorizationHeader);
+ username = jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_USERNAME);
+ tenantDomain = MultitenantUtils.getTenantDomain(username);
+ tenantId = Integer.parseInt(jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_TENANT_ID));
+ issuer = jwsObject.getJWTClaimsSet().getIssuer();
+ } catch (ParseException e) {
+ log.error("Error occurred while parsing JWT header.", e);
+ return null;
+ }
+ try {
- SignedJWT jwsObject = SignedJWT.parse(authorizationHeader);
- String username = jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_USERNAME);
- String tenantDomain = MultitenantUtils.getTenantDomain(username);
- int tenantId = Integer.parseInt(jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_TENANT_ID));
- String issuer = jwsObject.getJWTClaimsSet().getIssuer();
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
@@ -116,7 +127,7 @@ public class JWTAuthenticator implements WebappAuthenticator {
loadTenantRegistry(tenantId);
KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(tenantId);
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
- String alias = properties.getProperty(issuer);
+ String alias = properties == null ? null : properties.getProperty(issuer);
if (alias != null && !alias.isEmpty()) {
ServerConfiguration serverConfig = CarbonUtils.getServerConfiguration();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -139,10 +150,12 @@ public class JWTAuthenticator implements WebappAuthenticator {
publicKeyHolder.put(issuerAlias, publicKey);
}
}
-
//Get the filesystem keystore default primary certificate
- JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
- if (jwsObject.verify(verifier)) {
+ JWSVerifier verifier = null;
+ if (publicKey != null) {
+ verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
+ }
+ if (verifier != null && jwsObject.verify(verifier)) {
username = MultitenantUtils.getTenantAwareUsername(username);
if (tenantId == -1) {
log.error("tenantDomain is not valid. username : " + username + ", tenantDomain " +
@@ -162,9 +175,7 @@ public class JWTAuthenticator implements WebappAuthenticator {
}
} catch (UserStoreException e) {
log.error("Error occurred while obtaining the user.", e);
- } catch (ParseException e) {
- log.error("Error occurred while parsing the JWT header.", e);
- } catch (Exception e) {
+ } catch (Exception e) {
log.error("Error occurred while verifying the JWT header.", e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/BaseWebAppAuthenticatorFrameworkTest.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/BaseWebAppAuthenticatorFrameworkTest.java
index d4bcaf2e200..fc437004a00 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/BaseWebAppAuthenticatorFrameworkTest.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/BaseWebAppAuthenticatorFrameworkTest.java
@@ -21,18 +21,25 @@ package org.wso2.carbon.webapp.authenticator.framework;
import org.testng.annotations.BeforeSuite;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.core.internal.CarbonCoreDataHolder;
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionUtils;
+import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
+import org.wso2.carbon.registry.core.internal.RegistryDataHolder;
import org.wso2.carbon.registry.core.jdbc.realm.InMemoryRealmService;
+import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.user.api.Permission;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder;
+import org.wso2.carbon.webapp.authenticator.framework.util.TestTenantIndexingLoader;
+import org.wso2.carbon.webapp.authenticator.framework.util.TestTenantRegistryLoader;
import java.io.File;
+import java.io.InputStream;
import java.net.URL;
import static org.wso2.carbon.security.SecurityConstants.ADMIN_USER;
@@ -56,6 +63,17 @@ public class BaseWebAppAuthenticatorFrameworkTest {
.setTenantDomain(org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
PrivilegedCarbonContext.getThreadLocalCarbonContext()
.setTenantId(org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_ID);
+ CarbonCoreDataHolder.getInstance().setRegistryService(getRegistryService());
+ AuthenticatorFrameworkDataHolder.getInstance().setTenantRegistryLoader(new TestTenantRegistryLoader());
+ AuthenticatorFrameworkDataHolder.getInstance().setTenantIndexingLoader(new TestTenantIndexingLoader());
+ }
+
+ /**
+ * To get the registry service.
+ * @return RegistryService
+ * @throws RegistryException Registry Exception
+ */
+ private RegistryService getRegistryService() throws RegistryException, UserStoreException {
RealmService realmService = new InMemoryRealmService();
AuthenticatorFrameworkDataHolder.getInstance().setRealmService(realmService);
UserStoreManager userStoreManager = AuthenticatorFrameworkDataHolder.getInstance().getRealmService()
@@ -63,5 +81,12 @@ public class BaseWebAppAuthenticatorFrameworkTest {
Permission adminPermission = new Permission(PermissionUtils.ADMIN_PERMISSION_REGISTRY_PATH,
CarbonConstants.UI_PERMISSION_ACTION);
userStoreManager.addRole(ADMIN_ROLE + "t", new String[] { ADMIN_USER }, new Permission[] { adminPermission });
+ RegistryDataHolder.getInstance().setRealmService(realmService);
+ DeviceManagementDataHolder.getInstance().setRealmService(realmService);
+ InputStream is = BaseWebAppAuthenticatorFrameworkTest.class.getClassLoader()
+ .getResourceAsStream("carbon-home/repository/conf/registry.xml");
+ RegistryContext context = RegistryContext.getBaseInstance(is, realmService);
+ context.setSetup(true);
+ return context.getEmbeddedRegistryService();
}
}
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticatorTest.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticatorTest.java
new file mode 100644
index 00000000000..5ea9b1f88bd
--- /dev/null
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/JWTAuthenticatorTest.java
@@ -0,0 +1,109 @@
+package org.wso2.carbon.webapp.authenticator.framework.authenticator;
+
+import org.apache.catalina.connector.Request;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.wso2.carbon.base.MultitenantConstants;
+import org.wso2.carbon.identity.jwt.client.extension.dto.JWTConfig;
+import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
+import org.wso2.carbon.identity.jwt.client.extension.util.JWTClientUtil;
+import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
+import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder;
+import org.wso2.carbon.webapp.authenticator.framework.util.TestTenantIndexingLoader;
+import org.wso2.carbon.webapp.authenticator.framework.util.TestTenantRegistryLoader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class JWTAuthenticatorTest {
+ private JWTAuthenticator jwtAuthenticator;
+ private Field headersField;
+ private final String JWT_HEADER = "X-JWT-Assertion";
+ private String jwtToken;
+ private static final String SIGNED_JWT_AUTH_USERNAME = "http://wso2.org/claims/enduser";
+ private static final String SIGNED_JWT_AUTH_TENANT_ID = "http://wso2.org/claims/enduserTenantId";
+ private Properties properties;
+ private final String ISSUER = "wso2.org/products/iot";
+ private final String ALIAS = "wso2carbon";
+
+ @BeforeClass
+ public void setup() throws NoSuchFieldException, IOException, JWTClientException {
+ jwtAuthenticator = new JWTAuthenticator();
+ properties = new Properties();
+ properties.setProperty(ISSUER, ALIAS);
+ jwtAuthenticator.setProperties(properties);
+ headersField = org.apache.coyote.Request.class.getDeclaredField("headers");
+ headersField.setAccessible(true);
+ ClassLoader classLoader = getClass().getClassLoader();
+ URL resourceUrl = classLoader.getResource("jwt.properties");
+ File jwtPropertyFile;
+ JWTConfig jwtConfig = null;
+
+ if (resourceUrl != null) {
+ jwtPropertyFile = new File(resourceUrl.getFile());
+ Properties jwtConfigProperties = new Properties();
+ jwtConfigProperties.load(new FileInputStream(jwtPropertyFile));
+ jwtConfig = new JWTConfig(jwtConfigProperties);
+ }
+
+ Map customClaims = new HashMap<>();
+ customClaims.put(SIGNED_JWT_AUTH_USERNAME, "admin");
+ customClaims.put(SIGNED_JWT_AUTH_TENANT_ID, String.valueOf(MultitenantConstants.SUPER_TENANT_ID));
+ jwtToken = JWTClientUtil.generateSignedJWTAssertion("admin", jwtConfig, false, customClaims);
+ }
+
+ @Test(description = "This method tests the get methods in the JWTAuthenticator")
+ public void testGetMethods() {
+ Assert.assertEquals(jwtAuthenticator.getName(), "JWT", "GetName method returns wrong value");
+ Assert.assertNotNull(jwtAuthenticator.getProperties(), "Properties are not properly added to JWT "
+ + "Authenticator");
+ Assert.assertEquals(jwtAuthenticator.getProperties().size(), properties.size(),
+ "Added properties do not match with retrieved properties");
+ Assert.assertNull(jwtAuthenticator.getProperty("test"), "Retrieved a propety that was never added");
+ Assert.assertNotNull(jwtAuthenticator.getProperty(ISSUER), ALIAS);
+ }
+
+ @Test(description = "This method tests the canHandle method under different conditions of request")
+ public void testHandle() throws IllegalAccessException, NoSuchFieldException {
+ Request request = new Request();
+ org.apache.coyote.Request coyoteRequest = new org.apache.coyote.Request();
+ request.setCoyoteRequest(coyoteRequest);
+ Assert.assertFalse(jwtAuthenticator.canHandle(request));
+ MimeHeaders mimeHeaders = new MimeHeaders();
+ MessageBytes bytes = mimeHeaders.addValue(JWT_HEADER);
+ bytes.setString("test");
+ headersField.set(coyoteRequest, mimeHeaders);
+ request.setCoyoteRequest(coyoteRequest);
+ Assert.assertTrue(jwtAuthenticator.canHandle(request));
+ }
+
+ @Test(description = "This method tests authenticate method under the successful condition")
+ public void testAuthenticate() throws IllegalAccessException, NoSuchFieldException {
+ Request request = new Request();
+ org.apache.coyote.Request coyoteRequest = new org.apache.coyote.Request();
+ MimeHeaders mimeHeaders = new MimeHeaders();
+ MessageBytes bytes = mimeHeaders.addValue(JWT_HEADER);
+ bytes.setString(jwtToken);
+ headersField.set(coyoteRequest, mimeHeaders);
+ Field uriMB = org.apache.coyote.Request.class.getDeclaredField("uriMB");
+ uriMB.setAccessible(true);
+ bytes = MessageBytes.newInstance();
+ bytes.setString("test");
+ uriMB.set(coyoteRequest, bytes);
+ request.setCoyoteRequest(coyoteRequest);
+
+ AuthenticationInfo authenticationInfo = jwtAuthenticator.authenticate(request, null);
+ Assert.assertNotNull(authenticationInfo.getUsername(), "Proper authentication request is not properly "
+ + "authenticated by the JWTAuthenticator");
+ }
+}
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantIndexingLoader.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantIndexingLoader.java
new file mode 100644
index 00000000000..12203c35d83
--- /dev/null
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantIndexingLoader.java
@@ -0,0 +1,9 @@
+package org.wso2.carbon.webapp.authenticator.framework.util;
+
+import org.wso2.carbon.registry.indexing.service.TenantIndexingLoader;
+
+public class TestTenantIndexingLoader implements TenantIndexingLoader {
+ @Override public void loadTenantIndex(int i) {
+
+ }
+}
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantRegistryLoader.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantRegistryLoader.java
new file mode 100644
index 00000000000..1656e91bc08
--- /dev/null
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/util/TestTenantRegistryLoader.java
@@ -0,0 +1,11 @@
+package org.wso2.carbon.webapp.authenticator.framework.util;
+
+import org.wso2.carbon.registry.core.exceptions.RegistryException;
+import org.wso2.carbon.registry.core.service.TenantRegistryLoader;
+
+public class TestTenantRegistryLoader implements TenantRegistryLoader {
+ @Override
+ public void loadTenantRegistry(int i) throws RegistryException {
+
+ }
+}
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/client-truststore.jks b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/client-truststore.jks
new file mode 100644
index 00000000000..3b9fdfb9e84
Binary files /dev/null and b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/client-truststore.jks differ
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/wso2carbon.jks b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/wso2carbon.jks
new file mode 100644
index 00000000000..b4b6220baec
Binary files /dev/null and b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/carbon-home/repository/resources/security/wso2carbon.jks differ
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/jwt.properties b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/jwt.properties
new file mode 100644
index 00000000000..b7be2e296ac
--- /dev/null
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/jwt.properties
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+#
+# WSO2 Inc. licenses this file to you 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.
+#
+
+#issuer of the JWT
+iss=wso2.org/products/iot
+
+TokenEndpoint=https://${iot.gateway.host}:${iot.gateway.https.port}/token?tenantDomain=carbon.super
+
+#audience of JWT claim
+#comma seperated values
+aud=devicemgt
+
+#expiration time of JWT (number of minutes from the current time)
+exp=1000
+
+#issued at time of JWT (number of minutes from the current time)
+iat=0
+
+#nbf time of JWT (number of minutes from current time)
+nbf=0
+
+#skew between IDP and issuer(seconds)
+skew=0
+
+# JWT Id
+#jti=token123
+
+#KeyStore to cryptographic credentials
+KeyStore=target/test-classes/carbon-home/repository/resources/security/wso2carbon.jks
+
+#Password of the KeyStore
+KeyStorePassword=wso2carbon
+
+#Alias of the SP's private key
+PrivateKeyAlias=wso2carbon
+
+#Private key password to retrieve the private key used to sign
+#AuthnRequest and LogoutRequest messages
+PrivateKeyPassword=wso2carbon
+
+#this will be used as the default IDP config if there isn't any config available for tenants.
+default-jwt-client=false
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/testng.xml b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/testng.xml
index d166d4b15ec..21430713793 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/testng.xml
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/resources/testng.xml
@@ -31,6 +31,7 @@
+