|
|
|
@ -22,23 +22,24 @@ 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.core.util.KeyStoreManager;
|
|
|
|
|
import org.wso2.carbon.user.api.TenantManager;
|
|
|
|
|
import org.wso2.carbon.registry.core.exceptions.RegistryException;
|
|
|
|
|
import org.wso2.carbon.registry.core.service.TenantRegistryLoader;
|
|
|
|
|
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.AuthenticationInfo;
|
|
|
|
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticatorFrameworkDataHolder;
|
|
|
|
|
|
|
|
|
|
import java.security.PublicKey;
|
|
|
|
|
import java.security.interfaces.RSAPublicKey;
|
|
|
|
|
import java.text.ParseException;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Properties;
|
|
|
|
|
import java.util.StringTokenizer;
|
|
|
|
|
|
|
|
|
@ -48,10 +49,11 @@ import java.util.StringTokenizer;
|
|
|
|
|
public class JWTAuthenticator implements WebappAuthenticator {
|
|
|
|
|
|
|
|
|
|
private static final Log log = LogFactory.getLog(JWTAuthenticator.class);
|
|
|
|
|
public static final String SIGNED_JWT_AUTH_USERNAME = "http://wso2.org/claims/enduser";
|
|
|
|
|
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 static final String JWT_AUTHENTICATOR = "JWT";
|
|
|
|
|
private static final String JWT_ASSERTION_HEADER = "X-JWT-Assertion";
|
|
|
|
|
|
|
|
|
|
private static final Map<String, PublicKey> publicKeyHolder = new HashMap<>();
|
|
|
|
|
@Override
|
|
|
|
|
public void init() {
|
|
|
|
|
|
|
|
|
@ -79,21 +81,24 @@ public class JWTAuthenticator implements WebappAuthenticator {
|
|
|
|
|
authenticationInfo.setStatus(Status.CONTINUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Get the filesystem keystore default primary certificate
|
|
|
|
|
KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(MultitenantConstants.SUPER_TENANT_ID);
|
|
|
|
|
try {
|
|
|
|
|
keyStoreManager.getDefaultPrimaryCertificate();
|
|
|
|
|
String authorizationHeader = request.getHeader(JWT_ASSERTION_HEADER);
|
|
|
|
|
JWSVerifier verifier =
|
|
|
|
|
new RSASSAVerifier((RSAPublicKey) keyStoreManager.getDefaultPublicKey());
|
|
|
|
|
SignedJWT jwsObject = SignedJWT.parse(authorizationHeader);
|
|
|
|
|
String username = jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_USERNAME);
|
|
|
|
|
String tenantDomain = MultitenantUtils.getTenantDomain(username);
|
|
|
|
|
int tenantId = jwsObject.getJWTClaimsSet().getIntegerClaim(SIGNED_JWT_AUTH_TENANT_ID);
|
|
|
|
|
PublicKey publicKey = publicKeyHolder.get(tenantDomain);
|
|
|
|
|
if (publicKey == null) {
|
|
|
|
|
loadTenantRegistry(tenantId);
|
|
|
|
|
KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(tenantId);
|
|
|
|
|
publicKey = keyStoreManager.getDefaultPublicKey();
|
|
|
|
|
publicKeyHolder.put(tenantDomain, publicKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Get the filesystem keystore default primary certificate
|
|
|
|
|
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
|
|
|
|
|
if (jwsObject.verify(verifier)) {
|
|
|
|
|
String username = jwsObject.getJWTClaimsSet().getStringClaim(SIGNED_JWT_AUTH_USERNAME);
|
|
|
|
|
String tenantDomain = MultitenantUtils.getTenantDomain(username);
|
|
|
|
|
username = MultitenantUtils.getTenantAwareUsername(username);
|
|
|
|
|
TenantManager tenantManager = AuthenticatorFrameworkDataHolder.getInstance().getRealmService().
|
|
|
|
|
getTenantManager();
|
|
|
|
|
int tenantId = tenantManager.getTenantId(tenantDomain);
|
|
|
|
|
if (tenantId == -1) {
|
|
|
|
|
log.error("tenantDomain is not valid. username : " + username + ", tenantDomain " +
|
|
|
|
|
": " + tenantDomain);
|
|
|
|
@ -122,24 +127,6 @@ public class JWTAuthenticator implements WebappAuthenticator {
|
|
|
|
|
return authenticationInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String decodeAuthorizationHeader(String authorizationHeader) {
|
|
|
|
|
|
|
|
|
|
if (authorizationHeader == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
@ -159,4 +146,11 @@ public class JWTAuthenticator implements WebappAuthenticator {
|
|
|
|
|
public String getProperty(String name) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void loadTenantRegistry(int tenantId) throws RegistryException {
|
|
|
|
|
TenantRegistryLoader tenantRegistryLoader = AuthenticatorFrameworkDataHolder.getInstance().
|
|
|
|
|
getTenantRegistryLoader();
|
|
|
|
|
AuthenticatorFrameworkDataHolder.getInstance().getTenantIndexingLoader().loadTenantIndex(tenantId);
|
|
|
|
|
tenantRegistryLoader.loadTenantRegistry(tenantId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|