forked from community/device-mgt-core
parent
43926b64b4
commit
3fa17c12a7
@ -0,0 +1,181 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>identity-extensions</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>org.wso2.carbon.identity.jwt.client.extension</artifactId>
|
||||||
|
<packaging>bundle</packaging>
|
||||||
|
<name>WSO2 Carbon - Device Management JWT Client Extensions</name>
|
||||||
|
<description>WSO2 Carbon - Device Management JWT Client Extensions</description>
|
||||||
|
<url>http://wso2.org</url>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.governance</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.governance.api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.registry.api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.registry.core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.ws.commons.axiom</groupId>
|
||||||
|
<artifactId>axiom-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.utils</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.orbit.org.scannotation</groupId>
|
||||||
|
<artifactId>scannotation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.osgi</groupId>
|
||||||
|
<artifactId>org.eclipse.osgi</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.osgi</groupId>
|
||||||
|
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.tomcat</groupId>
|
||||||
|
<artifactId>tomcat</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.ws.rs</groupId>
|
||||||
|
<artifactId>jsr311-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.axis2.wso2</groupId>
|
||||||
|
<artifactId>axis2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-lang.wso2</groupId>
|
||||||
|
<artifactId>commons-lang</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.analytics</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.analytics.api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.registry</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.registry.indexing</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.orbit.com.nimbusds</groupId>
|
||||||
|
<artifactId>nimbus-jose-jwt</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple.wso2</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents.wso2</groupId>
|
||||||
|
<artifactId>httpcore</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.orbit.org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<version>1.4.0</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||||
|
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||||
|
<Bundle-Version>${carbon.device.mgt.version}</Bundle-Version>
|
||||||
|
<Bundle-Description>Device Management JWT Client Bundle</Bundle-Description>
|
||||||
|
<Private-Package>org.wso2.carbon.device.mgt.jwt.client.extension.internal</Private-Package>
|
||||||
|
<Export-Package>
|
||||||
|
!org.wso2.carbon.device.mgt.jwt.client.extension.internal,
|
||||||
|
org.wso2.carbon.device.mgt.jwt.client.extension.*
|
||||||
|
</Export-Package>
|
||||||
|
<Import-Package>
|
||||||
|
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
|
||||||
|
</Import-Package>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -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<NameValuePair> 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<NameValuePair> 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<NameValuePair> 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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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<String, JWTClient> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<String> 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<String> getAudience(String audience){
|
||||||
|
List<String> audiences = new ArrayList<String>();
|
||||||
|
for(String audi : audience.split(",")){
|
||||||
|
audiences.add(audi.trim());
|
||||||
|
}
|
||||||
|
return audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSkew() {
|
||||||
|
return skew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue