From 274d3e9aeb1414ba6cd4c61363c7d131e7c6c67c Mon Sep 17 00:00:00 2001 From: ayyoob Date: Sat, 4 Feb 2017 20:51:56 +0530 Subject: [PATCH] used jwt grant type instead of saml --- .../pom.xml | 4 +- .../src/test/resources/sample.xml | 8 +- .../devicemgt/app/modules/login.js | 6 +- .../app/modules/oauth/token-handler-utils.js | 82 +++++++------------ .../app/modules/oauth/token-handlers.js | 45 ++++++++++ .../app/units/cdmf.unit.footer/footer.hbs | 4 +- .../uuf-template-app/lib/modules/auth/auth.js | 70 ++++++++++++++++ .../pom.xml | 5 ++ .../grant/ExtendedJWTGrantHandler.java | 51 ++++++++++++ .../jwt/client/extension/JWTClient.java | 30 ++++++- .../extension/constant/JWTConstants.java | 1 + .../client/extension/dto/AccessTokenInfo.java | 9 ++ .../pom.xml | 4 +- .../src/main/resources/conf/cdm-config.xml | 9 +- .../src/main/resources/jwt.properties | 2 +- pom.xml | 8 +- 16 files changed, 263 insertions(+), 75 deletions(-) create mode 100644 components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTGrantHandler.java diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.integration.client/pom.xml b/components/apimgt-extensions/org.wso2.carbon.apimgt.integration.client/pom.xml index f8e67e64b9d..5a9ada7d421 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.integration.client/pom.xml +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.integration.client/pom.xml @@ -14,13 +14,13 @@ apimgt-extensions org.wso2.carbon.devicemgt - 2.0.14-SNAPSHOT + 2.0.16-SNAPSHOT ../pom.xml 4.0.0 org.wso2.carbon.apimgt.integration.client - 2.0.14-SNAPSHOT + 2.0.16-SNAPSHOT bundle WSO2 Carbon - API Management Integration Client WSO2 Carbon - API Management Integration Client diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/test/resources/sample.xml b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/test/resources/sample.xml index aa18e5d03b7..6542d9629b2 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/test/resources/sample.xml +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/test/resources/sample.xml @@ -36,10 +36,10 @@ - + false diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/login.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/login.js index d36e7af0ab8..166859f89b4 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/login.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/login.js @@ -26,7 +26,11 @@ var onFail; var utility = require("/app/modules/utility.js").utility; var apiWrapperUtil = require("/app/modules/oauth/token-handlers.js")["handlers"]; if (context.input.samlToken) { - apiWrapperUtil.setupTokenPairBySamlGrantType(context.user.username + '@' + context.user.domain, context.input.samlToken); + //apiWrapperUtil.setupTokenPairBySamlGrantType(context.user.username + '@' + context.user.domain, context.input.samlToken); + /** + * Since the user can be verified using the sso.client.js we can use JWT grant type to issue the token for the user. + */ + apiWrapperUtil.setupTokenPairByJWTGrantType(context.user.username + '@' + context.user.domain, context.input.samlToken); } else { apiWrapperUtil.setupTokenPairByPasswordGrantType(context.input.username, context.input.password); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js index b31febe79a2..109e67f7ac7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js @@ -22,6 +22,7 @@ var utils = function () { var deviceMgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var constants = require("/app/modules/constants.js"); var carbon = require("carbon"); + var authModule = require("/lib/modules/auth/auth.js").module; //noinspection JSUnresolvedVariable var Base64 = Packages.org.apache.commons.codec.binary.Base64; @@ -275,59 +276,34 @@ var utils = function () { } }; - publicMethods["getTokenPairAndScopesBySAMLGrantType"] = function (assertion, encodedClientAppCredentials, scopes) { - if (!assertion || !encodedClientAppCredentials || !scopes) { - log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving access token by saml " + - "grant type. No assertion, encoded client app credentials or scopes are " + - "found - getTokenPairAndScopesBySAMLGrantType(x, y, z)"); - return null; - } else { - var assertionXML = publicMethods.decode(assertion); - /* - TODO: make assertion extraction with proper parsing. - Since Jaggery XML parser seem to add formatting which causes signature verification to fail. - */ - var assertionStartMarker = " - - WSO2 CDMF v2.0.6 | © , + + WSO2 IoT Server 3.1.0 | © , Inc. All Rights Reserved.

{{/zone}} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/lib/modules/auth/auth.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/lib/modules/auth/auth.js index 93cffdbf862..fad0b27b99e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/lib/modules/auth/auth.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/uuf-template-app/lib/modules/auth/auth.js @@ -565,6 +565,76 @@ var module = {}; } }; + + /** + * saml token validation Service. + * @param request {Object} HTTP request + * @param response {Object} HTTP response + */ + module.ssoLogin = function (samlToken) { + var samlResponse = samlToken; + var ssoClient = require("sso").client; + var samlResponseObj; + + if (samlResponse) { + try { + samlResponseObj = ssoClient.getSamlObject(samlResponse); + } catch (e) { + log.error(e.message, e); + return; + } + + // This is a login response. + var ssoConfigs = getSsoConfigurations(); + var CarbonUtils = Packages.org.wso2.carbon.utils.CarbonUtils; + var keyStorePassword = CarbonUtils.getServerConfiguration().getFirstProperty("Security.TrustStore.Password"); + var keyStoreName = CarbonUtils.getServerConfiguration().getFirstProperty("Security.TrustStore.Location"); + var identityAlias = ssoConfigs[constants.APP_CONF_AUTH_MODULE_SSO_IDENTITY_ALIAS]; + var keyStoreParams = { + KEY_STORE_NAME: keyStoreName, + KEY_STORE_PASSWORD: keyStorePassword, + IDP_ALIAS: identityAlias + }; + var rsEnabled = ssoConfigs[constants.APP_CONF_AUTH_MODULE_SSO_RESPONSE_SIGNING_ENABLED]; + if (utils.parseBoolean(rsEnabled)) { + if (!ssoClient.validateSignature(samlResponseObj, keyStoreParams)) { + var msg = "Invalid signature found in the SAML response."; + log.error(msg); + return; + } + } + + if (!ssoClient.validateSamlResponse(samlResponseObj, ssoConfigs, keyStoreParams)) { + var msg = "Invalid SAML response found."; + log.error(msg); + return; + } + + /** + * @type {{sessionId: string, loggedInUser: string, sessionIndex: string, samlToken: + * string}} + */ + var ssoSession = ssoClient.decodeSAMLLoginResponse(samlResponseObj, samlResponse, + session.getId()); + if (ssoSession.sessionId) { + var ssoSessions = getSsoSessions(); + ssoSessions[ssoSession.sessionId] = ssoSession; + if (ssoSession.sessionIndex) { + var carbonUser = (require("carbon")).server.tenantUser(ssoSession.loggedInUser); + utils.setCurrentUser(carbonUser.username, carbonUser.domain, carbonUser.tenantId); + module.loadTenant(ssoSession.loggedInUser); + var user = {user: module.getCurrentUser()}; + return user; + } + } else { + var msg = "Cannot decode SAML login response."; + log.error(msg); + return; + } + + } + }; + /** * Load current user tenant * @param username logged user name diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml index 75239f0fb2a..7406555132b 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml @@ -58,6 +58,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.user.mgt + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth2.grant.jwt + @@ -83,6 +87,7 @@ org.wso2.carbon.device.mgt.oauth.extensions.* + org.wso2.carbon.identity.oauth2.grant.jwt;version="${carbon.identity.jwt.grant.version.range}", org.apache.commons.logging, org.osgi.service.component, org.wso2.carbon.identity.application.common.model;version="${carbon.identity.framework.version.range}", diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTGrantHandler.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTGrantHandler.java new file mode 100644 index 00000000000..90bba018517 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTGrantHandler.java @@ -0,0 +1,51 @@ +/* + * 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.oauth.extensions.handlers.grant; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.keymgt.ScopesIssuer; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.grant.jwt.JWTBearerGrantHandler; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +/** + * This sets up user with tenant aware username. + */ +@SuppressWarnings("unused") +public class ExtendedJWTGrantHandler extends JWTBearerGrantHandler { + private static Log log = LogFactory.getLog(ExtendedJWTGrantHandler.class); + + @Override + public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) { + return ScopesIssuer.getInstance().setScopes(tokReqMsgCtx); + } + + @Override + public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { + /** + * This is added to skip per tenant IDP creation. + */ + tokReqMsgCtx.getOauth2AccessTokenReqDTO().setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + return super.validateGrant(tokReqMsgCtx); + } +} 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 index ad7d5470901..dc51a2c9df6 100644 --- 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 @@ -80,6 +80,25 @@ public class JWTClient { return getTokenInfo(params, consumerKey, consumerSecret); } + public AccessTokenInfo getAccessToken(String encodedAppcredential, String username, String scopes) + throws JWTClientException { + List params = new ArrayList<>(); + params.add(new BasicNameValuePair(JWTConstants.GRANT_TYPE_PARAM_NAME, jwtConfig.getJwtGrantType())); + String assertion = JWTClientUtil.generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient); + if (assertion == null) { + throw new JWTClientException("JWT is not configured properly for user : " + username); + } + params.add(new BasicNameValuePair(JWTConstants.JWT_PARAM_NAME, assertion)); + if (scopes != null && !scopes.isEmpty()) { + params.add(new BasicNameValuePair(JWTConstants.SCOPE_PARAM_NAME, scopes)); + } + String decodedKey[] = getDecodedKey(encodedAppcredential); + if (decodedKey.length != 2) { + throw new JWTClientException("Invalid app credential"); + } + return getTokenInfo(params, decodedKey[0], decodedKey[1]); + } + public AccessTokenInfo getAccessToken(String consumerKey, String consumerSecret, String username, String scopes, Map paramsMap) throws JWTClientException { @@ -137,9 +156,12 @@ public class JWTClient { String accessToken = (String) jsonObject.get(JWTConstants.ACCESS_TOKEN_GRANT_TYPE_PARAM_NAME); if (accessToken != null && !accessToken.isEmpty()) { accessTokenInfo.setAccessToken(accessToken); - accessTokenInfo.setRefreshToken((String) jsonObject.get(JWTConstants.REFRESH_TOKEN_GRANT_TYPE_PARAM_NAME)); + accessTokenInfo.setRefreshToken((String) jsonObject.get( + JWTConstants.REFRESH_TOKEN_GRANT_TYPE_PARAM_NAME)); accessTokenInfo.setExpiresIn((Long) jsonObject.get(JWTConstants.OAUTH_EXPIRES_IN)); accessTokenInfo.setTokenType((String) jsonObject.get(JWTConstants.OAUTH_TOKEN_TYPE)); + accessTokenInfo.setScopes((String) jsonObject.get(JWTConstants.OAUTH_TOKEN_SCOPE)); + } return accessTokenInfo; } catch (MalformedURLException e) { @@ -161,7 +183,11 @@ public class JWTClient { return new String(Base64.encodeBase64((consumerKey + ":" + consumerSecret).getBytes())); } - public String getJwtToken(String username) throws JWTClientException { + private String[] getDecodedKey(String encodedKey) { + return (new String(Base64.decodeBase64((encodedKey).getBytes()))).split(":"); + } + + public String getJwtToken(String username) throws JWTClientException { return JWTClientUtil.generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient); } 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 index ab6a4b142d1..998813054a3 100644 --- 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 @@ -23,6 +23,7 @@ package org.wso2.carbon.identity.jwt.client.extension.constant; public class JWTConstants { public static final String OAUTH_EXPIRES_IN = "expires_in"; public static final String OAUTH_TOKEN_TYPE = "token_type"; + public static final String OAUTH_TOKEN_SCOPE = "scope"; public static final String JWT_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"; public static final String GRANT_TYPE_PARAM_NAME = "grant_type"; public static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_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/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 index c1adb813fd4..a0240dc8189 100644 --- 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 @@ -27,6 +27,7 @@ public class AccessTokenInfo { private long expiresIn; private String refreshToken; private String accessToken; + private String scopes; public String getTokenType() { return tokenType; @@ -59,4 +60,12 @@ public class AccessTokenInfo { public void setAccessToken(String accessToken) { this.accessToken = accessToken; } + + public String getScopes() { + return scopes; + } + + public void setScopes(String scopes) { + this.scopes = scopes; + } } diff --git a/features/apimgt-extensions/org.wso2.carbon.apimgt.integration.client.feature/pom.xml b/features/apimgt-extensions/org.wso2.carbon.apimgt.integration.client.feature/pom.xml index 15c8f907397..e6c65be7614 100644 --- a/features/apimgt-extensions/org.wso2.carbon.apimgt.integration.client.feature/pom.xml +++ b/features/apimgt-extensions/org.wso2.carbon.apimgt.integration.client.feature/pom.xml @@ -22,13 +22,13 @@ org.wso2.carbon.devicemgt apimgt-extensions-feature - 2.0.14-SNAPSHOT + 2.0.16-SNAPSHOT ../pom.xml 4.0.0 org.wso2.carbon.apimgt.integration.client.feature - 2.0.14-SNAPSHOT + 2.0.16-SNAPSHOT pom WSO2 Carbon - APIM Integration Client Feature http://wso2.org diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml index e48531dd83a..c747b4354c6 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml @@ -28,8 +28,8 @@ org.wso2.carbon.device.mgt.extensions.push.notification.provider.gcm.GCMBasedPushNotificationProvider - - + org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt.MQTTBasedPushNotificationProvider + org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp.XMPPBasedPushNotificationProvider https://localhost:9443 @@ -47,11 +47,6 @@ Simple - - android - ios - windows - diff --git a/features/jwt-client/org.wso2.carbon.identity.jwt.client.extension.feature/src/main/resources/jwt.properties b/features/jwt-client/org.wso2.carbon.identity.jwt.client.extension.feature/src/main/resources/jwt.properties index 3c384655811..b0d9a4c18d7 100644 --- a/features/jwt-client/org.wso2.carbon.identity.jwt.client.extension.feature/src/main/resources/jwt.properties +++ b/features/jwt-client/org.wso2.carbon.identity.jwt.client.extension.feature/src/main/resources/jwt.properties @@ -19,7 +19,7 @@ #issuer of the JWT iss=wso2.org/products/iot -TokenEndpoint=https://${iot.keymanager.host}:${iot.keymanager.https.port}/oauth2/token +TokenEndpoint=https://${iot.gateway.host}:${iot.gateway.https.port}/token #audience of JWT claim #comma seperated values diff --git a/pom.xml b/pom.xml index 1c40349604c..9bbaf653fa0 100644 --- a/pom.xml +++ b/pom.xml @@ -909,6 +909,11 @@ org.wso2.carbon.identity.oauth.stub ${identity.inbound.auth.oauth.version} + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth2.grant.jwt + ${carbon.identity.jwt.grant.version} + org.wso2.carbon.identity.framework org.wso2.carbon.identity.application.authentication.framework @@ -1769,7 +1774,8 @@ [5.0.0, 6.0.0) 5.3.1 5.3.0 - + 1.0.2 + [1.0.2, 2.0.0) [5.7.0, 6.0.0) [5.2.0, 6.0.0)