From 3fa17c12a73a24819e5bd7c030f6b1c16e01d3e3 Mon Sep 17 00:00:00 2001 From: prabathabey Date: Sun, 27 Mar 2016 13:02:35 +0530 Subject: [PATCH] merging jwt client extension component --- .../pom.xml | 181 +++++++++++++ .../jwt/client/extension/JWTClient.java | 248 ++++++++++++++++++ .../client/extension/JWTClientManager.java | 136 ++++++++++ .../extension/constant/JWTConstants.java | 28 ++ .../client/extension/dto/AccessTokenInfo.java | 62 +++++ .../jwt/client/extension/dto/JWTConfig.java | 147 +++++++++++ .../JWTClientAlreadyExistsException.java | 44 ++++ .../JWTClientConfigurationException.java | 43 +++ .../exception/JWTClientException.java | 41 +++ .../JWTClientExtensionDataHolder.java | 91 +++++++ .../JWTClientExtensionServiceComponent.java | 134 ++++++++++ .../client/extension/util/JWTClientUtil.java | 168 ++++++++++++ components/identity-extensions/pom.xml | 2 +- .../pom.xml | 2 +- 14 files changed, 1325 insertions(+), 2 deletions(-) create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/pom.xml create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClientManager.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/constant/JWTConstants.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/AccessTokenInfo.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/JWTConfig.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientAlreadyExistsException.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientConfigurationException.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientException.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionDataHolder.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionServiceComponent.java create mode 100644 components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/util/JWTClientUtil.java diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/pom.xml b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/pom.xml new file mode 100644 index 0000000000..965bf90b0b --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/pom.xml @@ -0,0 +1,181 @@ + + + + + + + org.wso2.carbon.devicemgt + identity-extensions + 1.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.identity.jwt.client.extension + bundle + WSO2 Carbon - Device Management JWT Client Extensions + WSO2 Carbon - Device Management JWT Client Extensions + http://wso2.org + + + + org.wso2.carbon.governance + org.wso2.carbon.governance.api + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + org.wso2.carbon + org.wso2.carbon.registry.core + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.apache.ws.commons.axiom + axiom-api + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.orbit.org.scannotation + scannotation + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.tomcat + tomcat + + + org.wso2.tomcat + tomcat-servlet-api + + + javax.ws.rs + jsr311-api + + + org.apache.axis2.wso2 + axis2 + + + commons-lang.wso2 + commons-lang + + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.api + + + org.wso2.carbon.registry + org.wso2.carbon.registry.indexing + + + org.wso2.orbit.com.nimbusds + nimbus-jose-jwt + + + com.googlecode.json-simple.wso2 + json-simple + + + org.apache.httpcomponents.wso2 + httpcore + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + + + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.device.mgt.version} + Device Management JWT Client Bundle + org.wso2.carbon.device.mgt.jwt.client.extension.internal + + !org.wso2.carbon.device.mgt.jwt.client.extension.internal, + org.wso2.carbon.device.mgt.jwt.client.extension.* + + + org.osgi.framework, + org.osgi.service.component, + org.wso2.carbon.governance.api.*, + org.wso2.carbon.context, + org.wso2.carbon.registry.core, + org.wso2.carbon.registry.core.exceptions, + org.wso2.carbon.registry.core.session, + org.wso2.carbon.utils, + org.apache.commons.logging, + org.wso2.carbon.registry.core.*;resolution:=optional, + org.wso2.carbon.registry.common.*;version="${carbon.registry.imp.pkg.version.range}", + org.wso2.carbon.registry.indexing.*; version="${carbon.registry.imp.pkg.version.range}", + com.nimbusds.jwt.*;version="${nimbus.orbit.version.range}", + com.nimbusds.jose.*;version="${nimbus.orbit.version.range}", + javax.net.ssl, + org.apache.commons.codec.binary, + org.apache.commons.io, + org.apache.http;version="${httpclient.version.range}", + org.apache.http.client;version="${httpclient.version.range}", + org.apache.http.message;version="${httpclient.version.range}", + org.apache.http.client;version="${httpclient.version.range}", + org.apache.http.impl;version="${httpclient.version.range}", + org.apache.http.conn.*;version="${httpclient.version.range}", + org.apache.http.util;version="${httpclient.version.range}", + org.apache.http.client.entity;version="${httpclient.version.range}", + org.apache.http.client.methods;version="${httpclient.version.range}", + org.apache.http.impl.client;version="${httpclient.version.range}", + org.json.simple.*, + org.wso2.carbon.core.util, + javax.net.ssl, + org.wso2.carbon.user.core.service, + org.wso2.carbon.user.core.tenant + + + + + + + + \ No newline at end of file diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java new file mode 100644 index 0000000000..0aa903d29a --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java @@ -0,0 +1,248 @@ +/* + * 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. + */ + +package org.wso2.carbon.device.mgt.jwt.client.extension; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicNameValuePair; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.core.util.KeyStoreManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.constant.JWTConstants; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.JWTConfig; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.device.mgt.jwt.client.extension.util.JWTClientUtil; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +/** + * this class represents an implementation of Token Client which is based on JWT + */ +public class JWTClient { + + private static Log log = LogFactory.getLog(JWTClient.class); + private static final String JWT_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + private static final String GRANT_TYPE_PARAM_NAME = "grant_type"; + private static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token"; + private static final String REFRESH_TOKEN_GRANT_TYPE_PARAM_NAME = "refresh_token"; + private static final String JWT_PARAM_NAME = "assertion"; + private static final String SCOPE_PARAM_NAME = "scope"; + private JWTConfig jwtConfig; + + public JWTClient(JWTConfig jwtConfig) { + this.jwtConfig = jwtConfig; + } + + /** + * {@inheritDoc} + */ + public AccessTokenInfo getAccessToken(String consumerKey, String consumerSecret, String username, String scopes) + throws JWTClientException { + List params = new ArrayList<>(); + params.add(new BasicNameValuePair(GRANT_TYPE_PARAM_NAME, JWT_GRANT_TYPE)); + String assertion = generateSignedJWTAssertion(username); + if (assertion == null) { + throw new JWTClientException("JWT is not configured properly for user : " + username); + } + params.add(new BasicNameValuePair(JWT_PARAM_NAME, assertion)); + params.add(new BasicNameValuePair(SCOPE_PARAM_NAME, scopes)); + return getTokenInfo(params, consumerKey, consumerSecret); + } + + /** + * {@inheritDoc} + */ + public AccessTokenInfo getAccessTokenFromRefreshToken(String refreshToken, String username, String scopes, + String consumerKey, String consumerSecret) + throws JWTClientException { + List params = new ArrayList<>(); + params.add(new BasicNameValuePair(GRANT_TYPE_PARAM_NAME, REFRESH_TOKEN_GRANT_TYPE)); + params.add(new BasicNameValuePair(REFRESH_TOKEN_GRANT_TYPE_PARAM_NAME, refreshToken)); + params.add(new BasicNameValuePair(SCOPE_PARAM_NAME, scopes)); + return getTokenInfo(params, consumerKey, consumerSecret); + } + + + private AccessTokenInfo getTokenInfo(List nameValuePairs, String consumerKey, String consumerSecret) + throws JWTClientException { + String response = null; + try { + if (jwtConfig == null) { + return null; + } + URL tokenEndpoint = new URL(jwtConfig.getTokenEndpoint()); + HttpClient httpClient = JWTClientUtil.getHttpClient(tokenEndpoint.getProtocol()); + HttpPost postMethod = new HttpPost(tokenEndpoint.toString()); + postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs)); + postMethod.addHeader("Authorization", "Basic " + getBase64Encode(consumerKey, consumerSecret)); + postMethod.addHeader("Content-Type", "application/x-www-form-urlencoded"); + HttpResponse httpResponse = httpClient.execute(postMethod); + response = JWTClientUtil.getResponseString(httpResponse); + if (log.isDebugEnabled()) { + log.debug(response); + } + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObject = (JSONObject) jsonParser.parse(response); + AccessTokenInfo accessTokenInfo = new AccessTokenInfo(); + accessTokenInfo.setAccess_token((String) jsonObject.get(JWTConstants.OAUTH_ACCESS_TOKEN)); + accessTokenInfo.setRefresh_token((String) jsonObject.get(JWTConstants.OAUTH_REFRESH_TOKEN)); + accessTokenInfo.setExpires_in((Long) jsonObject.get(JWTConstants.OAUTH_EXPIRES_IN)); + accessTokenInfo.setToken_type((String) jsonObject.get(JWTConstants.OAUTH_TOKEN_TYPE)); + return accessTokenInfo; + } catch (MalformedURLException e) { + throw new JWTClientException("Invalid URL for token endpoint " + jwtConfig.getTokenEndpoint(), e); + } catch (ParseException e) { + throw new JWTClientException("Error when parsing the response " + response, e); + } catch (IOException e) { + throw new JWTClientException("Error when reading the response from buffer.", e); + } catch (NoSuchAlgorithmException e) { + throw new JWTClientException("No such algorithm found when loading the ssl socket", e); + } catch (KeyStoreException e) { + throw new JWTClientException("Failed loading the keystore.", e); + } catch (KeyManagementException e) { + throw new JWTClientException("Failed setting up the ssl http client.", e); + } + } + + private String getBase64Encode(String consumerKey, String consumerSecret) { + return new String(Base64.encodeBase64((consumerKey + ":" + consumerSecret).getBytes())); + } + + public String generateSignedJWTAssertion(String username) throws JWTClientException { + try { + String subject = username; + long currentTimeMillis = System.currentTimeMillis(); + // add the skew between servers + String iss = jwtConfig.getIssuer(); + if (iss == null || iss.isEmpty()) { + return null; + } + currentTimeMillis += jwtConfig.getSkew(); + long iat = currentTimeMillis + jwtConfig.getIssuedInternal() * 60 * 1000; + long exp = currentTimeMillis + jwtConfig.getExpirationTime() * 60 * 1000; + long nbf = currentTimeMillis + jwtConfig.getValidityPeriodFromCurrentTime() * 60 * 1000; + String jti = jwtConfig.getJti(); + if (jti == null) { + String defaultTokenId = currentTimeMillis + "" + new Random().nextInt(); + jti = defaultTokenId; + } + List aud = jwtConfig.getAudiences(); + //set up the basic claims + JWTClaimsSet claimsSet = new JWTClaimsSet(); + claimsSet.setIssueTime(new Date(iat)); + claimsSet.setExpirationTime(new Date(exp)); + claimsSet.setIssuer(iss); + claimsSet.setSubject(username); + claimsSet.setNotBeforeTime(new Date(nbf)); + claimsSet.setJWTID(jti); + claimsSet.setAudience(aud); + + // get Keystore params + String keyStorePath = jwtConfig.getKeyStorePath(); + String privateKeyAlias = jwtConfig.getPrivateKeyAlias(); + String privateKeyPassword = jwtConfig.getPrivateKeyPassword(); + KeyStore keyStore; + RSAPrivateKey rsaPrivateKey; + if (keyStorePath != null && !keyStorePath.isEmpty()) { + String keyStorePassword = jwtConfig.getKeyStorePassword(); + keyStore = loadKeyStore(new File(keyStorePath), keyStorePassword, "JKS"); + rsaPrivateKey = (RSAPrivateKey) keyStore.getKey(privateKeyAlias, privateKeyPassword.toCharArray()); + } else { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); + KeyStoreManager tenantKeyStoreManager = KeyStoreManager.getInstance(tenantId); + rsaPrivateKey = (RSAPrivateKey) tenantKeyStoreManager.getDefaultPrivateKey(); + } + JWSSigner signer = new RSASSASigner(rsaPrivateKey); + SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet); + signedJWT.sign(signer); + String assertion = signedJWT.serialize(); + return assertion; + } catch (KeyStoreException e) { + throw new JWTClientException("Failed loading the keystore.", e); + } catch (IOException e) { + throw new JWTClientException("Failed parsing the keystore file.", e); + } catch (NoSuchAlgorithmException e) { + throw new JWTClientException("No such algorithm found RS256.", e); + } catch (CertificateException e) { + throw new JWTClientException("Failed loading the certificate from the keystore.", e); + } catch (UnrecoverableKeyException e) { + throw new JWTClientException("Failed loading the keys from the keystore.", e); + } catch (JOSEException e) { + throw new JWTClientException(e); + } catch (Exception e) { + //This is thrown when loading default private key. + throw new JWTClientException("Failed loading the private key.", e); + } + } + + private KeyStore loadKeyStore(final File keystoreFile, final String password, final String keyStoreType) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + if (null == keystoreFile) { + throw new IllegalArgumentException("Keystore url may not be null"); + } + URI keystoreUri = keystoreFile.toURI(); + URL keystoreUrl = keystoreUri.toURL(); + KeyStore keystore = KeyStore.getInstance(keyStoreType); + InputStream is = null; + try { + is = keystoreUrl.openStream(); + keystore.load(is, null == password ? null : password.toCharArray()); + } finally { + if (null != is) { + is.close(); + } + } + return keystore; + } +} + + + diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClientManager.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClientManager.java new file mode 100644 index 0000000000..cafed79cb9 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClientManager.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.wso2.carbon.device.mgt.jwt.client.extension; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.JWTConfig; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientAlreadyExistsException; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientConfigurationException; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.device.mgt.jwt.client.extension.util.JWTClientUtil; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; + +import java.io.IOException; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This creates JWT Client for each tenant. + */ +public class JWTClientManager { + + private static Map jwtClientMap; + private static JWTClientManager jwtClientCreator; + private static final Log log = LogFactory.getLog(JWTClientManager.class); + private static final String TENANT_JWT_CONFIG_LOCATION = "/jwt-config/jwt.properties"; + + public static JWTClientManager getInstance() { + if (jwtClientCreator == null) { + synchronized (JWTClientManager.class) { + if (jwtClientCreator == null) { + jwtClientCreator = new JWTClientManager(); + } + } + } + return jwtClientCreator; + } + + private JWTClientManager() { + jwtClientMap = new ConcurrentHashMap<>(); + } + + /** + * this return the jwt based token client to generate token for the tenant. + */ + public JWTClient getJWTClient() throws JWTClientException { + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); + //Get jwt client which has been registered for the tenant. + JWTClient jwtClient = getJWTClient(tenantDomain); + if (jwtClient == null) { + //Create new jwt client for the tenant. + try { + JWTConfig jwtConfig = new JWTConfig(getJWTConfig(tenantId)); + jwtClient = new JWTClient(jwtConfig); + addJWTClient(tenantDomain, jwtClient); + } catch (JWTClientAlreadyExistsException e) { + log.warn("Attempting to register a jwt client for the tenant " + tenantDomain + + " when one already exists. Returning existing jwt client"); + return getJWTClient(tenantDomain); + } catch (JWTClientConfigurationException e) { + throw new JWTClientException("Failed to parse jwt configuration for tenant " + tenantDomain, e); + } + } + return jwtClient; + } + + /** + * Fetch the jwt client which has been registered under the tenant domain. + * + * @param tenantDomain - The tenant domain under which the jwt client is registered + * @return - Instance of the jwt client which was registered. Null if not registered. + */ + private JWTClient getJWTClient(String tenantDomain) { + if (jwtClientMap.containsKey(tenantDomain)) { + return jwtClientMap.get(tenantDomain); + } + return null; + } + + /** + * Adds a jwt client to the jwt client map. + * + * @param tenantDomain - The tenant domain under which the jwt client will be registered. + * @param jwtClient - Instance of the jwt client + * @throws JWTClientAlreadyExistsException - If a jwt client has already been registered under the tenantdomain + */ + private void addJWTClient(String tenantDomain, JWTClient jwtClient) throws JWTClientAlreadyExistsException { + if (jwtClientMap.containsKey(tenantDomain)) { + throw new JWTClientAlreadyExistsException("A jwt client has already been created for the tenant " + tenantDomain); + } + jwtClientMap.put(tenantDomain, jwtClient); + } + + /** + * Retrieve JWT configs from registry. + */ + private Properties getJWTConfig(int tenantId) throws JWTClientConfigurationException { + try { + Resource config = JWTClientUtil.getConfigRegistryResourceContent(tenantId, TENANT_JWT_CONFIG_LOCATION); + Properties properties = new Properties(); + if(config != null) { + properties.load(config.getContentStream()); + } else { + throw new JWTClientConfigurationException("Failed to load jwt configuration for tenant id : " + tenantId); + } + return properties; + } catch (RegistryException e) { + throw new JWTClientConfigurationException("Failed to load the content from registry for tenant " + + tenantId, e); + } catch (IOException e) { + throw new JWTClientConfigurationException( + "Failed to parse the content from the registry for tenant " + tenantId, e); + } + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/constant/JWTConstants.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/constant/JWTConstants.java new file mode 100644 index 0000000000..41358fe627 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/constant/JWTConstants.java @@ -0,0 +1,28 @@ +/* + * 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.device.mgt.jwt.client.extension.constant; + +/** + * This holds the constants related JWT client component. + */ +public class JWTConstants { + public static final String OAUTH_ACCESS_TOKEN = "access_token"; + public static final String OAUTH_REFRESH_TOKEN = "refresh_token"; + public static final String OAUTH_EXPIRES_IN = "expires_in"; + public static final String OAUTH_TOKEN_TYPE = "token_type"; +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/AccessTokenInfo.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/AccessTokenInfo.java new file mode 100644 index 0000000000..9c12c653ff --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/AccessTokenInfo.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.wso2.carbon.device.mgt.jwt.client.extension.dto; + +/** + * This holds the token information that return from the token endpoint. + */ +public class AccessTokenInfo { + + private String token_type; + private long expires_in; + private String refresh_token; + private String access_token; + + public String getToken_type() { + return token_type; + } + + public void setToken_type(String token_type) { + this.token_type = token_type; + } + + public long getExpires_in() { + return expires_in; + } + + public void setExpires_in(long expres_in) { + this.expires_in = expres_in; + } + + public String getRefresh_token() { + return refresh_token; + } + + public void setRefresh_token(String refresh_token) { + this.refresh_token = refresh_token; + } + + public String getAccess_token() { + return access_token; + } + + public void setAccess_token(String access_token) { + this.access_token = access_token; + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/JWTConfig.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/JWTConfig.java new file mode 100644 index 0000000000..6c41ae8c03 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/dto/JWTConfig.java @@ -0,0 +1,147 @@ +package org.wso2.carbon.device.mgt.jwt.client.extension.dto; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class JWTConfig { + + private static final String JWT_ISSUER = "iss"; + private static final String JWT_EXPIRATION_TIME = "exp"; + private static final String JWT_AUDIENCE = "aud"; + private static final String VALIDITY_PERIOD = "nbf"; + private static final String JWT_TOKEN_ID = "jti"; + private static final String JWT_ISSUED_AT = "iat"; + private static final String SERVER_TIME_SKEW="skew"; + private static final String JKS_PATH ="KeyStore"; + private static final String JKS_PRIVATE_KEY_ALIAS ="PrivateKeyAlias"; + private static final String JKS_PASSWORD ="KeyStorePassword"; + private static final String JKA_PRIVATE_KEY_PASSWORD = "PrivateKeyPassword"; + private static final String TOKEN_ENDPOINT = "TokenEndpoint"; + + /** + * issuer of the JWT + */ + private String issuer; + + /** + * skew between IDP and issuer(milliseconds) + */ + private int skew; + + /** + * Audience of JWT claim + */ + private List audiences; + + /** + * expiration time of JWT (number of minutes from the current time). + */ + private int expirationTime; + + /** + * issued Interval from current time of JWT (number of minutes from the current time). + */ + private int issuedInternal; + + /** + * nbf time of JWT (number of minutes from current time). + */ + private int validityPeriodInterval; + + /** + * JWT Id. + */ + private String jti; + + /** + * Token Endpoint; + */ + private String tokenEndpoint; + + /** + * Configuration for keystore. + */ + private String keyStorePath; + private String keyStorePassword; + private String privateKeyAlias; + private String privateKeyPassword; + + /** + * @param properties load the config from the properties file. + */ + public JWTConfig(Properties properties) { + issuer = properties.getProperty(JWT_ISSUER, null); + skew = Integer.parseInt(properties.getProperty(SERVER_TIME_SKEW, "0")); + issuedInternal = Integer.parseInt(properties.getProperty(JWT_ISSUED_AT,"0")); + expirationTime = Integer.parseInt(properties.getProperty(JWT_EXPIRATION_TIME,"15")); + validityPeriodInterval = Integer.parseInt(properties.getProperty(VALIDITY_PERIOD,"0")); + jti = properties.getProperty(JWT_TOKEN_ID, null); + String audience = properties.getProperty(JWT_AUDIENCE, null); + if(audience != null) { + audiences = getAudience(audience); + } + //get Keystore params + keyStorePath = properties.getProperty(JKS_PATH); + keyStorePassword = properties.getProperty(JKS_PASSWORD); + privateKeyAlias = properties.getProperty(JKS_PRIVATE_KEY_ALIAS); + privateKeyPassword = properties.getProperty(JKA_PRIVATE_KEY_PASSWORD); + tokenEndpoint = properties.getProperty(TOKEN_ENDPOINT, ""); + } + + private static List getAudience(String audience){ + List audiences = new ArrayList(); + for(String audi : audience.split(",")){ + audiences.add(audi.trim()); + } + return audiences; + } + + public String getIssuer() { + return issuer; + } + + public int getSkew() { + return skew; + } + + public List getAudiences() { + return audiences; + } + + public int getExpirationTime() { + return expirationTime; + } + + public int getIssuedInternal() { + return issuedInternal; + } + + public int getValidityPeriodFromCurrentTime() { + return validityPeriodInterval; + } + + public String getJti() { + return jti; + } + + public String getKeyStorePath() { + return keyStorePath; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public String getPrivateKeyAlias() { + return privateKeyAlias; + } + + public String getPrivateKeyPassword() { + return privateKeyPassword; + } + + public String getTokenEndpoint() { + return tokenEndpoint; + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientAlreadyExistsException.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientAlreadyExistsException.java new file mode 100644 index 0000000000..cdcbfb64b2 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientAlreadyExistsException.java @@ -0,0 +1,44 @@ +/* + * 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. + * + */ + +package org.wso2.carbon.device.mgt.jwt.client.extension.exception; + +public class JWTClientAlreadyExistsException extends Exception { + public JWTClientAlreadyExistsException() { + super(); + } + + public JWTClientAlreadyExistsException(String message) { + super(message); + } + + public JWTClientAlreadyExistsException(String message, Throwable cause) { + super(message, cause); + } + + public JWTClientAlreadyExistsException(Throwable cause) { + super(cause); + } + + protected JWTClientAlreadyExistsException(String message, Throwable cause, + boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientConfigurationException.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientConfigurationException.java new file mode 100644 index 0000000000..a7f9d742d4 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientConfigurationException.java @@ -0,0 +1,43 @@ +/* + * 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. + * + */ +package org.wso2.carbon.device.mgt.jwt.client.extension.exception; + +public class JWTClientConfigurationException extends Exception { + public JWTClientConfigurationException() { + super(); + } + + public JWTClientConfigurationException(String message) { + super(message); + } + + public JWTClientConfigurationException(String message, Throwable cause) { + super(message, cause); + } + + public JWTClientConfigurationException(Throwable cause) { + super(cause); + } + + protected JWTClientConfigurationException(String message, Throwable cause, + boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientException.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientException.java new file mode 100644 index 0000000000..e434fbcb23 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/exception/JWTClientException.java @@ -0,0 +1,41 @@ +/* + * 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. + * + */ +package org.wso2.carbon.device.mgt.jwt.client.extension.exception; + +public class JWTClientException extends Exception{ + public JWTClientException() { + super(); + } + + public JWTClientException(String message) { + super(message); + } + + public JWTClientException(String message, Throwable cause) { + super(message, cause); + } + + public JWTClientException(Throwable cause) { + super(cause); + } + + protected JWTClientException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionDataHolder.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionDataHolder.java new file mode 100644 index 0000000000..39d50961a7 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionDataHolder.java @@ -0,0 +1,91 @@ +/* + * 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. + * + */ +package org.wso2.carbon.device.mgt.jwt.client.extension.internal; + +import org.wso2.carbon.registry.core.service.RegistryService; +import org.wso2.carbon.registry.core.service.TenantRegistryLoader; +import org.wso2.carbon.registry.indexing.service.TenantIndexingLoader; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.user.core.tenant.TenantManager; + +public class JWTClientExtensionDataHolder { + private static JWTClientExtensionDataHolder thisInstance = new JWTClientExtensionDataHolder(); + + private TenantRegistryLoader tenantRegistryLoader; + private TenantIndexingLoader indexLoader; + private RegistryService registryService; + private RealmService realmService; + private TenantManager tenantManager; + + private JWTClientExtensionDataHolder() { + } + + + public static JWTClientExtensionDataHolder getInstance() { + return thisInstance; + } + + + public void setTenantRegistryLoader(TenantRegistryLoader tenantRegistryLoader){ + this.tenantRegistryLoader = tenantRegistryLoader; + } + + public TenantRegistryLoader getTenantRegistryLoader(){ + return tenantRegistryLoader; + } + + public void setIndexLoaderService(TenantIndexingLoader indexLoader) { + this.indexLoader = indexLoader; + } + + public TenantIndexingLoader getIndexLoaderService(){ + return indexLoader; + } + + public RegistryService getRegistryService() { + return registryService; + } + + public void setRegistryService(RegistryService registryService) { + this.registryService = registryService; + } + + public RealmService getRealmService() { + if (realmService == null) { + throw new IllegalStateException("Realm service is not initialized properly"); + } + return realmService; + } + + public void setRealmService(RealmService realmService) { + this.realmService = realmService; + this.setTenantManager(realmService); + } + + private void setTenantManager(RealmService realmService) { + if (realmService == null) { + throw new IllegalStateException("Realm service is not initialized properly"); + } + this.tenantManager = realmService.getTenantManager(); + } + + public TenantManager getTenantManager() { + return tenantManager; + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionServiceComponent.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionServiceComponent.java new file mode 100644 index 0000000000..72dd99a56d --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/internal/JWTClientExtensionServiceComponent.java @@ -0,0 +1,134 @@ +/* + * 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. + * + */ +package org.wso2.carbon.device.mgt.jwt.client.extension.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.device.mgt.jwt.client.extension.util.JWTClientUtil; +import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.core.service.RegistryService; +import org.wso2.carbon.registry.core.service.TenantRegistryLoader; +import org.wso2.carbon.registry.indexing.service.TenantIndexingLoader; +import org.wso2.carbon.user.core.service.RealmService; +import java.io.IOException; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.jwt.client.extension.internal.JWTClientExtensionServiceComponent" + * immediate="true" + * @scr.reference name="registry.service" + * interface="org.wso2.carbon.registry.core.service.RegistryService" + * cardinality="1..1" + * policy="dynamic" + * bind="setRegistryService" + * unbind="unsetRegistryService" + * @scr.reference name="tenant.registryloader" + * interface="org.wso2.carbon.registry.core.service.TenantRegistryLoader" + * cardinality="1..1" + * policy="dynamic" + * bind="setTenantRegistryLoader" + * unbind="unsetTenantRegistryLoader" + * @scr.reference name="tenant.indexloader" + * interface="org.wso2.carbon.registry.indexing.service.TenantIndexingLoader" + * cardinality="1..1" + * policy="dynamic" + * bind="setIndexLoader" + * unbind="unsetIndexLoader" + * @scr.reference name="realm.service" + * interface="org.wso2.carbon.user.core.service.RealmService" + * cardinality="1..1" + * policy="dynamic" + * bind="setRealmService" + * unbind="unsetRealmService" + */ +public class JWTClientExtensionServiceComponent { + + private static Log log = LogFactory.getLog(JWTClientExtensionServiceComponent.class); + + protected void activate(ComponentContext componentContext) { + if (log.isDebugEnabled()) { + log.debug("Initializing jwt extension bundle"); + } + try { + JWTClientUtil.initialize(); + } catch (RegistryException e) { + log.error("Failed loading the jwt config from registry.", e); + } catch (IOException e) { + log.error("Failed loading the jwt config from the file system.", e); + } + } + + protected void deactivate(ComponentContext componentContext) { + //do nothing + } + + protected void setRegistryService(RegistryService registryService) { + if (registryService != null && log.isDebugEnabled()) { + log.debug("Registry service initialized"); + } + JWTClientExtensionDataHolder.getInstance().setRegistryService(registryService); + } + + protected void unsetRegistryService(RegistryService registryService) { + JWTClientExtensionDataHolder.getInstance().setRegistryService(null); + } + + protected void setTenantRegistryLoader(TenantRegistryLoader tenantRegistryLoader) { + JWTClientExtensionDataHolder.getInstance().setTenantRegistryLoader(tenantRegistryLoader); + } + + protected void unsetTenantRegistryLoader(TenantRegistryLoader tenantRegistryLoader) { + JWTClientExtensionDataHolder.getInstance().setTenantRegistryLoader(null); + } + + protected void setIndexLoader(TenantIndexingLoader indexLoader) { + if (indexLoader != null && log.isDebugEnabled()) { + log.debug("IndexLoader service initialized"); + } + JWTClientExtensionDataHolder.getInstance().setIndexLoaderService(indexLoader); + } + + protected void unsetIndexLoader(TenantIndexingLoader indexLoader) { + JWTClientExtensionDataHolder.getInstance().setIndexLoaderService(null); + } + + /** + * Sets Realm Service. + * + * @param realmService An instance of RealmService + */ + protected void setRealmService(RealmService realmService) { + if (log.isDebugEnabled()) { + log.debug("Setting Realm Service"); + } + JWTClientExtensionDataHolder.getInstance().setRealmService(realmService); + } + + /** + * Unsets Realm Service. + * + * @param realmService An instance of RealmService + */ + protected void unsetRealmService(RealmService realmService) { + if (log.isDebugEnabled()) { + log.debug("Unsetting Realm Service"); + } + JWTClientExtensionDataHolder.getInstance().setRealmService(null); + } +} diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/util/JWTClientUtil.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/util/JWTClientUtil.java new file mode 100644 index 0000000000..087fd17294 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/util/JWTClientUtil.java @@ -0,0 +1,168 @@ +/* + * 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. + */ +package org.wso2.carbon.device.mgt.jwt.client.extension.util; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.jwt.client.extension.internal.JWTClientExtensionDataHolder; +import org.wso2.carbon.registry.core.Registry; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.core.service.RegistryService; +import org.wso2.carbon.registry.core.service.TenantRegistryLoader; +import org.wso2.carbon.utils.CarbonUtils; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +/** + * This is the utility class that is used for JWT Client. + */ +public class JWTClientUtil { + + private static final Log log = LogFactory.getLog(JWTClientUtil.class); + private static final String HTTPS_PROTOCOL = "https"; + private static final String TENANT_JWT_CONFIG_LOCATION = "/jwt-config/jwt.properties"; + private static final String JWT_CONFIG_FILE_NAME = "jwt.properties"; + private static final String SUPERTENANT_JWT_CONFIG_LOCATION = + CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + JWT_CONFIG_FILE_NAME; + /** + * Return a http client instance + * @param protocol- service endpoint protocol http/https + * @return + */ + public static HttpClient getHttpClient(String protocol) + throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { + HttpClient httpclient; + if (HTTPS_PROTOCOL.equals(protocol)) { + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build()); + httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } else { + httpclient = HttpClients.createDefault(); + } + return httpclient; + } + + public static String getResponseString(HttpResponse httpResponse) throws IOException { + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); + String readLine; + String response = ""; + while (((readLine = br.readLine()) != null)) { + response += readLine; + } + return response; + } finally { + EntityUtils.consumeQuietly(httpResponse.getEntity()); + if (br != null) { + try { + br.close(); + } catch (IOException e) { + log.warn("Error while closing the connection! " + e.getMessage()); + } + } + } + } + + public static void initialize() throws RegistryException, IOException { + Resource resource = getConfigRegistryResourceContent(MultitenantConstants.SUPER_TENANT_ID, TENANT_JWT_CONFIG_LOCATION); + if (resource == null) { + File configFile = new File(SUPERTENANT_JWT_CONFIG_LOCATION); + String contents = FileUtils.readFileToString(configFile, "UTF-8"); + addJWTConfigResourceToRegistry(MultitenantConstants.SUPER_TENANT_ID, contents); + } + } + + /** + * Get the jwt details from the registry for tenants. + * + * @param tenantId for identify tenant space. + * @param registryLocation retrive the config file from tenant space. + * @return the config for tenant + * @throws RegistryException + */ + public static Resource getConfigRegistryResourceContent(int tenantId, final String registryLocation) + throws RegistryException { + try { + Resource resource = null; + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true); + RegistryService registryService = JWTClientExtensionDataHolder.getInstance().getRegistryService(); + if (registryService != null) { + Registry registry = registryService.getConfigSystemRegistry(tenantId); + JWTClientUtil.loadTenantRegistry(tenantId); + if (registry.resourceExists(registryLocation)) { + resource = registry.get(registryLocation); + } + } + return resource; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Get the jwt details from the registry for tenants. + * + * @param tenantId for accesing tenant space. + * @return the config for tenant + * @throws RegistryException + */ + public static void addJWTConfigResourceToRegistry(int tenantId, String content) + throws RegistryException { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true); + RegistryService registryService = JWTClientExtensionDataHolder.getInstance().getRegistryService(); + if (registryService != null) { + Registry registry = registryService.getConfigSystemRegistry(tenantId); + JWTClientUtil.loadTenantRegistry(tenantId); + if (!registry.resourceExists(TENANT_JWT_CONFIG_LOCATION)) { + Resource resource = registry.newResource(); + resource.setContent(content.getBytes()); + registry.put(TENANT_JWT_CONFIG_LOCATION, resource); + } + } + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + private static void loadTenantRegistry(int tenantId) throws RegistryException { + TenantRegistryLoader tenantRegistryLoader = JWTClientExtensionDataHolder.getInstance().getTenantRegistryLoader(); + JWTClientExtensionDataHolder.getInstance().getIndexLoaderService().loadTenantIndex(tenantId); + tenantRegistryLoader.loadTenantRegistry(tenantId); + } +} diff --git a/components/identity-extensions/pom.xml b/components/identity-extensions/pom.xml index e63415d853..b55a9102fe 100644 --- a/components/identity-extensions/pom.xml +++ b/components/identity-extensions/pom.xml @@ -29,13 +29,13 @@ 4.0.0 org.wso2.carbon.devicemgt identity-extensions - 1.1.0-SNAPSHOT pom WSO2 Carbon - Dynamic Client Registration Component http://wso2.org org.wso2.carbon.device.mgt.oauth.extensions + org.wso2.carbon.identity.jwt.client.extension dynamic-client-registration backend-oauth-authenticator 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 c72eae9bf5..08114db190 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 @@ -199,7 +199,7 @@ org.wso2.carbon.device.mgt.common - org.apache.httpcomponents.wso2 + org.wso2.orbit.org.apache.httpcomponents httpclient