Added JWT authenticator

merge-requests/7/head
harshanl 9 years ago
parent f2b8f978f5
commit e1da84ec55

@ -37,6 +37,10 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
@ -45,16 +49,47 @@
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Bundle-Activator>org.wso2.carbon.webapp.authenticator.framework.internal.WebappAuthenticatorFrameworkBundleActivator</Bundle-Activator>
<!--<Require-Bundle>org.wso2.carbon.tomcat.patch</Require-Bundle>-->
<Private-Package>
org.wso2.carbon.webapp.authenticator.framework.internal
</Private-Package>
<DynamicImport-Package>*</DynamicImport-Package>
<Export-Package>
!org.wso2.carbon.webapp.authenticator.framework.internal,
org.wso2.carbon.webapp.authenticator.framework.*
</Export-Package>
<Import-Package>
com.nimbusds.jose,
com.nimbusds.jose.crypto,
com.nimbusds.jwt,
javax.xml.bind,
javax.xml.bind.annotation,
javax.xml.parsers,
javax.xml.validation,
org.apache.axiom.util.base64,
org.apache.catalina,
org.apache.catalina.connector,
org.apache.catalina.util,
org.apache.commons.logging,
org.apache.coyote,
org.apache.tomcat.util.buf,
org.apache.tomcat.util.http,
org.osgi.service.component,
org.w3c.dom,
org.wso2.carbon.apimgt.api,
org.wso2.carbon.apimgt.core.authenticate,
org.wso2.carbon.apimgt.core.gateway,
org.wso2.carbon.apimgt.impl.dto,
org.wso2.carbon.context,
org.wso2.carbon.core.util,
org.wso2.carbon.identity.base,
org.wso2.carbon.identity.core.util,
org.wso2.carbon.tomcat.ext.valves,
org.wso2.carbon.user.api,
org.wso2.carbon.user.core.service,
org.wso2.carbon.user.core.tenant,
org.wso2.carbon.utils,
org.wso2.carbon.utils.multitenancy,
org.xml.sax
</Import-Package>
<!--<Fragment-Host>tomcat</Fragment-Host>-->
</instructions>
</configuration>
@ -103,6 +138,10 @@
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.core.services</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.orbit.com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
</dependencies>
</project>

@ -18,19 +18,34 @@
*/
package org.wso2.carbon.webapp.authenticator.framework;
import org.wso2.carbon.user.core.service.RealmService;
public class DataHolder {
private static WebappAuthenticatorRepository repository;
private WebappAuthenticatorRepository repository;
private RealmService realmService;
private DataHolder() {}
public static void setWebappAuthenticatorRepository (WebappAuthenticatorRepository repository) {
DataHolder.repository = repository;
private static DataHolder thisInstance = new DataHolder();
public static DataHolder getInstance() {
return thisInstance;
}
public void setWebappAuthenticatorRepository (WebappAuthenticatorRepository repository) {
this.repository = repository;
}
public static WebappAuthenticatorRepository getWebappAuthenticatorRepository() {
public WebappAuthenticatorRepository getWebappAuthenticatorRepository() {
return repository;
}
public RealmService getRealmService() {
return realmService;
}
public void setRealmService(RealmService realmService) {
this.realmService = realmService;
}
}

@ -18,18 +18,9 @@
*/
package org.wso2.carbon.webapp.authenticator.framework;
import org.apache.catalina.connector.Request;
import org.apache.catalina.util.Base64;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.MessageBytes;
import org.wso2.carbon.webapp.authenticator.framework.authenticator.BasicAuthAuthenticator;
import org.wso2.carbon.webapp.authenticator.framework.authenticator.OAuthAuthenticator;
public class WebappAuthenticatorFactory {
public static WebappAuthenticator getAuthenticator(String authScheme) {
return DataHolder.getWebappAuthenticatorRepository().getAuthenticator(authScheme);
return DataHolder.getInstance().getWebappAuthenticatorRepository().getAuthenticator(authScheme);
}
}

@ -0,0 +1,140 @@
/*
* Copyright (c) 2015, 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.
*/
package org.wso2.carbon.webapp.authenticator.framework.authenticator;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jwt.SignedJWT;
import org.apache.axiom.util.base64.Base64Utils;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.KeyStoreManager;
import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.carbon.webapp.authenticator.framework.DataHolder;
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticator;
import java.security.interfaces.RSAPublicKey;
import java.text.ParseException;
import java.util.StringTokenizer;
/**
* This authenticator authenticates HTTP requests using JWT header.
*/
public class JWTAuthenticator implements WebappAuthenticator {
private static final Log log = LogFactory.getLog(JWTAuthenticator.class);
public static final String SIGNED_JWT_AUTH_USERNAME = "Username";
private static final String JWT_AUTHENTICATOR = "JWT";
@Override
public boolean isAuthenticated(Request request) {
return false;
}
@Override
public Status authenticate(Request request, Response response) {
String requestUri = request.getRequestURI();
if (requestUri == null || "".equals(requestUri)) {
return Status.CONTINUE;
}
StringTokenizer tokenizer = new StringTokenizer(requestUri, "/");
String context = tokenizer.nextToken();
if (context == null || "".equals(context)) {
return Status.CONTINUE;
}
if (log.isDebugEnabled()) {
log.debug("Authenticating using JWT header.");
}
//Get the filesystem keystore default primary certificate
KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(
MultitenantConstants.SUPER_TENANT_ID);
try {
keyStoreManager.getDefaultPrimaryCertificate();
String authorizationHeader = request.getHeader(HTTPConstants.HEADER_AUTHORIZATION);
String headerData = decodeAuthorizationHeader(authorizationHeader);
JWSVerifier verifier =
new RSASSAVerifier((RSAPublicKey) keyStoreManager.getDefaultPublicKey());
SignedJWT jwsObject = SignedJWT.parse(headerData);
if (jwsObject.verify(verifier)) {
String username = jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_USERNAME);
String tenantDomain = MultitenantUtils.getTenantDomain(username);
username = MultitenantUtils.getTenantAwareUsername(username);
TenantManager tenantManager = DataHolder.getInstance().getRealmService().getTenantManager();
int tenantId = tenantManager.getTenantId(tenantDomain);
if (tenantId == -1) {
log.error("tenantDomain is not valid. username : " + username + ", tenantDomain " +
": " + tenantDomain);
return Status.FAILURE;
}
UserStoreManager userStore = DataHolder.getInstance().getRealmService().
getTenantUserRealm(tenantId).getUserStoreManager();
if (userStore.isExistingUser(username)) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantId(tenantId);
ctx.setUsername(username);
return Status.SUCCESS;
}
}
} catch (UserStoreException e) {
log.error("Error occurred while obtaining the user.", e);
return Status.FAILURE;
} catch (ParseException e) {
log.error("Error occurred while parsing the JWT header.", e);
return Status.FAILURE;
} catch (JOSEException e) {
log.error("Error occurred while verifying the JWT header.", e);
return Status.FAILURE;
} catch (Exception e) {
log.error("Error occurred while verifying the JWT header.", e);
return Status.FAILURE;
}
return Status.CONTINUE;
}
private String decodeAuthorizationHeader(String authorizationHeader) {
String[] splitValues = authorizationHeader.trim().split(" ");
byte[] decodedBytes = Base64Utils.decode(splitValues[1].trim());
if (decodedBytes != null) {
return new String(decodedBytes);
} else {
if (log.isDebugEnabled()) {
log.debug("Error decoding authorization header.");
}
return null;
}
}
@Override
public String getName() {
return JWTAuthenticator.JWT_AUTHENTICATOR;
}
}

@ -69,12 +69,13 @@ public class OAuthAuthenticator implements WebappAuthenticator {
try {
if (Constants.NO_MATCHING_AUTH_SCHEME.equals(authLevel)) {
AuthenticationFrameworkUtil.handleNoMatchAuthScheme(request, response, request.getMethod(),
apiVersion, context);
apiVersion, context);
return Status.CONTINUE;
} else {
String bearerToken = this.getBearerToken(request);
boolean isAuthenticated =
AuthenticationFrameworkUtil.doAuthenticate(context, apiVersion, bearerToken, authLevel, domain);
AuthenticationFrameworkUtil.doAuthenticate(context, apiVersion,
bearerToken, authLevel, domain);
return (isAuthenticated) ? Status.SUCCESS : Status.FAILURE;
}
} catch (APIManagementException e) {
@ -94,7 +95,8 @@ public class OAuthAuthenticator implements WebappAuthenticator {
private String getBearerToken(Request request) {
MessageBytes authorization =
request.getCoyoteRequest().getMimeHeaders().getValue(Constants.HTTPHeaders.HEADER_HTTP_AUTHORIZATION);
request.getCoyoteRequest().getMimeHeaders().
getValue(Constants.HTTPHeaders.HEADER_HTTP_AUTHORIZATION);
String tokenValue = null;
if (authorization != null) {

@ -20,10 +20,10 @@ package org.wso2.carbon.webapp.authenticator.framework.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve;
import org.wso2.carbon.tomcat.ext.valves.TomcatValveContainer;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.webapp.authenticator.framework.DataHolder;
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticator;
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticatorFrameworkValve;
@ -34,25 +34,34 @@ import org.wso2.carbon.webapp.authenticator.framework.config.WebappAuthenticator
import java.util.ArrayList;
import java.util.List;
public class WebappAuthenticatorFrameworkBundleActivator implements BundleActivator {
private static final Log log = LogFactory.getLog(WebappAuthenticatorFrameworkBundleActivator.class);
/**
* @scr.component name="org.wso2.carbon.webapp.authenticator" immediate="true"
* @scr.reference name="user.realmservice.default"
* interface="org.wso2.carbon.user.core.service.RealmService"
* cardinality="1..1"
* policy="dynamic"
* bind="setRealmService"
* unbind="unsetRealmService"
*/
public class WebappAuthenticatorFrameworkServiceComponent {
private static final Log log = LogFactory.getLog(WebappAuthenticatorFrameworkServiceComponent.class);
@Override
public void start(BundleContext bundleContext) throws Exception {
@SuppressWarnings("unused")
protected void activate(ComponentContext componentContext) {
if (log.isDebugEnabled()) {
log.debug("Starting Web Application Authenticator Framework Bundle");
}
try {
WebappAuthenticatorConfig.init();
WebappAuthenticatorRepository repository = new WebappAuthenticatorRepository();
for (AuthenticatorConfig config : WebappAuthenticatorConfig.getInstance().getAuthenticators()) {
WebappAuthenticator authenticator =
(WebappAuthenticator) Class.forName(config.getClassName()).newInstance();
repository.addAuthenticator(authenticator);
}
DataHolder.setWebappAuthenticatorRepository(repository);
DataHolder.getInstance().setWebappAuthenticatorRepository(repository);
List<CarbonTomcatValve> valves = new ArrayList<CarbonTomcatValve>();
valves.add(new WebappAuthenticatorFrameworkValve());
@ -66,9 +75,19 @@ public class WebappAuthenticatorFrameworkBundleActivator implements BundleActiva
}
}
@Override
public void stop(BundleContext bundleContext) throws Exception {
@SuppressWarnings("unused")
protected void deactivate(ComponentContext componentContext) {
//do nothing
}
protected void setRealmService(RealmService realmService) {
if (log.isDebugEnabled()) {
log.debug("RealmService acquired");
}
DataHolder.getInstance().setRealmService(realmService);
}
protected void unsetRealmService(RealmService realmService) {
DataHolder.getInstance().setRealmService(null);
}
}

@ -558,6 +558,11 @@
<artifactId>axis2</artifactId>
<version>${axis2.orbit.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.orbit.com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>${nimbus.orbit.version}</version>
</dependency>
<!-- End of Orbit dependencies -->
@ -1251,6 +1256,9 @@
<!-- JSCEP -->
<jscep.version>2.0.2.wso2v2</jscep.version>
<!-- Nimbus Jose-->
<nimbus.orbit.version>2.26.1.wso2v3</nimbus.orbit.version>
</properties>
</project>

Loading…
Cancel
Save