Merge branch 'corrective-policy' into 'master'

Implement OIDC Based SSO For All React Applications

Closes product-iots#656

See merge request entgra/carbon-device-mgt!680
revert-70ac1926
Dharmakeerthi Lasantha 4 years ago
commit d9386901d4

@ -1,4 +1,5 @@
{ {
"appName": "publisher",
"theme": { "theme": {
"logo": "https://entgra.io/assets/images/svg/logo.svg", "logo": "https://entgra.io/assets/images/svg/logo.svg",
"primaryColor": "rgb(24, 144, 255)", "primaryColor": "rgb(24, 144, 255)",
@ -14,7 +15,10 @@
}, },
"loginUri": "/publisher-ui-request-handler/login", "loginUri": "/publisher-ui-request-handler/login",
"logoutUri": "/publisher-ui-request-handler/logout", "logoutUri": "/publisher-ui-request-handler/logout",
"platform": "publisher" "ssoLoginUri": "/publisher-ui-request-handler/ssoLogin",
"ssoLogoutUri": "/publisher-ui-request-handler/ssoLogout",
"platform": "publisher",
"appUiConfigUri": "/api/device-mgt-config/v1.0/configurations/ui-config"
}, },
"defaultPlatformIcons": { "defaultPlatformIcons": {
"default": { "default": {

@ -23,6 +23,7 @@ import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import { Layout, Spin, Result } from 'antd'; import { Layout, Spin, Result } from 'antd';
import ConfigContext from './components/ConfigContext'; import ConfigContext from './components/ConfigContext';
import { getUiConfig } from './services/utils/uiConfigHandler';
const { Content } = Layout; const { Content } = Layout;
const loadingView = ( const loadingView = (
@ -161,12 +162,29 @@ class App extends React.Component {
const redirectUrl = encodeURI(window.location.href); const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname; const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1); const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment !== 'login') { getUiConfig(config).then(uiConfig => {
window.location.href = if (uiConfig !== undefined) {
window.location.origin + `/publisher/login?redirect=${redirectUrl}`; if (uiConfig.isSsoEnable) {
} else { window.location =
this.getAndroidEnterpriseToken(config); window.location.origin +
} config.serverConfig.ssoLoginUri +
'?redirect=' +
window.location.origin +
pageURL;
} else if (lastURLSegment !== 'login') {
window.location.href =
window.location.origin +
`/${config.appName}/login?redirect=${redirectUrl}`;
} else {
this.getAndroidEnterpriseToken(config);
}
} else {
this.setState({
loading: false,
error: true,
});
}
});
} else { } else {
this.setState({ this.setState({
loading: false, loading: false,

@ -21,6 +21,7 @@ import { LogoutOutlined } from '@ant-design/icons';
import { notification, Menu } from 'antd'; import { notification, Menu } from 'antd';
import axios from 'axios'; import axios from 'axios';
import { withConfigContext } from '../../../../components/ConfigContext'; import { withConfigContext } from '../../../../components/ConfigContext';
import { getUiConfig } from '../../../../services/utils/uiConfigHandler';
/* /*
This class for call the logout api by sending request This class for call the logout api by sending request
@ -44,27 +45,38 @@ class Logout extends React.Component {
inValid: false, inValid: false,
}); });
axios let logoutUri;
.post(window.location.origin + config.serverConfig.logoutUri) getUiConfig(config).then(uiConfig => {
.then(res => { if (uiConfig !== undefined) {
// if the api call status is correct then user will logout and then it goes to login page if (uiConfig.isSsoEnable) {
if (res.status === 200) { logoutUri = window.location.origin + config.serverConfig.ssoLogoutUri;
window.location = window.location.origin + '/publisher/login';
}
})
.catch(function(error) {
if (error.hasOwnProperty('response') && error.response.status === 400) {
thisForm.setState({
inValid: true,
});
} else { } else {
notification.error({ logoutUri = window.location.origin + config.serverConfig.logoutUri;
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to logout.',
});
} }
}); axios
.post(logoutUri)
.then(res => {
// if the api call status is correct then user
// will logout and then it goes to login page
if (res.status === 200) {
window.location =
window.location.origin + `/${config.appName}/login`;
}
})
.catch(function(error) {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to logout.',
});
});
} else {
this.setState({
loading: false,
error: true,
});
}
});
}; };
render() { render() {

@ -0,0 +1,40 @@
/*
* Copyright (C) 2020. Entgra (Pvt) Ltd, https://entgra.io
* All Rights Reserved.
*
* Unauthorized copying/redistribution of this file, via any medium
* is strictly prohibited.
* Proprietary and confidential.
*
* Licensed under the Entgra Commercial License,
* Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.
*
* You may obtain a copy of the License at
* https://entgra.io/licenses/entgra-commercial/1.0
*/
import axios from 'axios';
import { notification } from 'antd';
export const getUiConfig = config => {
return axios
.get(window.location.origin + config.serverConfig.appUiConfigUri)
.then(res => {
return res.data;
})
.catch(error => {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load UI configurations.',
});
});
};

@ -1,4 +1,5 @@
{ {
"appName": "store",
"theme": { "theme": {
"type": "default", "type": "default",
"value": "lightBaseTheme", "value": "lightBaseTheme",
@ -17,7 +18,10 @@
}, },
"loginUri": "/store-ui-request-handler/login", "loginUri": "/store-ui-request-handler/login",
"logoutUri": "/store-ui-request-handler/logout", "logoutUri": "/store-ui-request-handler/logout",
"platform": "store" "ssoLoginUri": "/store-ui-request-handler/ssoLogin",
"ssoLogoutUri": "/store-ui-request-handler/ssoLogout",
"platform": "store",
"appUiConfigUri": "/api/device-mgt-config/v1.0/configurations/ui-config"
}, },
"defaultPlatformIcons": { "defaultPlatformIcons": {
"default": { "default": {

@ -21,8 +21,9 @@ import 'antd/dist/antd.less';
import RouteWithSubRoutes from './components/RouteWithSubRoutes'; import RouteWithSubRoutes from './components/RouteWithSubRoutes';
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import { Layout, Spin, Result } from 'antd'; import { Layout, Result, Spin } from 'antd';
import ConfigContext from './components/context/ConfigContext'; import ConfigContext from './components/context/ConfigContext';
import { getUiConfig } from './services/utils/uiConfigHandler';
const { Content } = Layout; const { Content } = Layout;
const loadingView = ( const loadingView = (
@ -138,15 +139,32 @@ class App extends React.Component {
const redirectUrl = encodeURI(window.location.href); const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname; const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1); const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment !== 'login') { getUiConfig(config).then(uiConfig => {
window.location.href = if (uiConfig !== undefined) {
window.location.origin + `/store/login?redirect=${redirectUrl}`; if (uiConfig.isSsoEnable) {
} else { window.location =
this.setState({ window.location.origin +
loading: false, config.serverConfig.ssoLoginUri +
config: config, '?redirect=' +
}); window.location.origin +
} pageURL;
} else if (lastURLSegment !== 'login') {
window.location.href =
window.location.origin +
`/${config.appName}/login?redirect=${redirectUrl}`;
} else {
this.setState({
loading: false,
config: config,
});
}
} else {
this.setState({
loading: false,
error: true,
});
}
});
} else { } else {
this.setState({ this.setState({
loading: false, loading: false,

@ -22,6 +22,7 @@ import { Menu } from 'antd';
import axios from 'axios'; import axios from 'axios';
import { withConfigContext } from '../../../../components/context/ConfigContext'; import { withConfigContext } from '../../../../components/context/ConfigContext';
import { handleApiError } from '../../../../services/utils/errorHandler'; import { handleApiError } from '../../../../services/utils/errorHandler';
import { getUiConfig } from '../../../../services/utils/uiConfigHandler';
/* /*
This class for call the logout api by sending request This class for call the logout api by sending request
@ -45,20 +46,34 @@ class Logout extends React.Component {
inValid: false, inValid: false,
}); });
axios let logoutUri;
.post(window.location.origin + config.serverConfig.logoutUri) getUiConfig(config).then(uiConfig => {
.then(res => { if (uiConfig !== undefined) {
// if the api call status is correct then user will logout and then it goes to login page if (uiConfig.isSsoEnable) {
if (res.status === 200) { logoutUri = window.location.origin + config.serverConfig.ssoLogoutUri;
window.location = window.location.origin + '/store/login'; } else {
logoutUri = window.location.origin + config.serverConfig.logoutUri;
} }
}) axios
.catch(function(error) { .post(logoutUri)
handleApiError( .then(res => {
error, // if the api call status is correct then user
'Error occurred while trying to get your review.', // will logout and then it goes to login page
); if (res.status === 200) {
}); window.location =
window.location.origin + `/${config.appName}/login`;
}
})
.catch(function(error) {
handleApiError(error, 'Error occurred while trying to logout.');
});
} else {
this.setState({
loading: false,
error: true,
});
}
});
}; };
render() { render() {

@ -0,0 +1,40 @@
/*
* Copyright (C) 2020. Entgra (Pvt) Ltd, https://entgra.io
* All Rights Reserved.
*
* Unauthorized copying/redistribution of this file, via any medium
* is strictly prohibited.
* Proprietary and confidential.
*
* Licensed under the Entgra Commercial License,
* Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.
*
* You may obtain a copy of the License at
* https://entgra.io/licenses/entgra-commercial/1.0
*/
import axios from 'axios';
import { notification } from 'antd';
export const getUiConfig = config => {
return axios
.get(window.location.origin + config.serverConfig.appUiConfigUri)
.then(res => {
return res.data;
})
.catch(error => {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load UI configurations.',
});
});
};

@ -29,7 +29,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form id="consentForm" method="POST" action="/commonauth"> <form id="consentForm" method="POST" action={{action}}>
<p>By selecting following attributes I agree to share them with the above service provider.</p> <p>By selecting following attributes I agree to share them with the above service provider.</p>
{{#unless singleMandatoryClaim}} {{#unless singleMandatoryClaim}}
<div class="wr-input-control"> <div class="wr-input-control">
@ -60,9 +60,9 @@
</div> </div>
<p class="small">Mandatory claims are marked with an asterisk ( * )</p> <p class="small">Mandatory claims are marked with an asterisk ( * )</p>
<div class="wr-input-control wr-btn-grp"> <div class="wr-input-control wr-btn-grp">
<input type="hidden" name="sessionDataKey" value="{{sessionDataKey}}"/> <input type="hidden" name="{{sessionDataKeyName}}" value="{{sessionDataKey}}"/>
<input type="hidden" name="consent" id="consent" value="deny"/> <input type="hidden" name="consent" id="consent" value="deny"/>
<button class="btn btn-primary" onclick="approved()">Approve</button> <button class="btn btn-primary" onclick="approved('{{ssoProtocol}}')">Approve</button>
<button class="btn btn-default" onclick="deny()">Deny</button> <button class="btn btn-default" onclick="deny()">Deny</button>
</div> </div>
</form> </form>
@ -72,4 +72,4 @@
{{/zone}} {{/zone}}
{{#zone "bottomJs"}} {{#zone "bottomJs"}}
{{js "js/script.js"}} {{js "js/script.js"}}
{{/zone}} {{/zone}}

@ -1,7 +1,21 @@
function onRequest(context) { function onRequest(context) {
var Encode = Packages.org.owasp.encoder.Encode; var Encode = Packages.org.owasp.encoder.Encode;
var viewModel = {}; var viewModel = {};
viewModel.appName = Encode.forHtml(request.getParameter("sp"));
// if sp is received, its a saml request or else its oidc
if(request.getParameter("sp") !== null) {
viewModel.appName = Encode.forHtml(request.getParameter("sp"));
viewModel.action = "/commonauth";
viewModel.sessionDataKey = Encode.forHtmlAttribute(request.getParameter("sessionDataKey"));
viewModel.sessionDataKeyName = "sessionDataKey";
viewModel.ssoProtocol = "saml";
} else {
viewModel.appName = Encode.forHtml(request.getParameter("application"));
viewModel.action = "../oauth2/authorize";
viewModel.sessionDataKey = Encode.forHtmlAttribute(request.getParameter("sessionDataKeyConsent"));
viewModel.sessionDataKeyName = "sessionDataKeyConsent";
viewModel.ssoProtocol = "oidc";
}
var mandatoryClaims = []; var mandatoryClaims = [];
var requestedClaims = []; var requestedClaims = [];
var singleMandatoryClaim = false; var singleMandatoryClaim = false;
@ -36,6 +50,5 @@ function onRequest(context) {
viewModel.mandatoryClaims = mandatoryClaims; viewModel.mandatoryClaims = mandatoryClaims;
viewModel.requestedClaims = requestedClaims; viewModel.requestedClaims = requestedClaims;
viewModel.singleMandatoryClaim = singleMandatoryClaim; viewModel.singleMandatoryClaim = singleMandatoryClaim;
viewModel.sessionDataKey = Encode.forHtmlAttribute(request.getParameter("sessionDataKey"));
return viewModel; return viewModel;
} }

@ -1,9 +1,13 @@
function approved() { function approved(ssoProtocol) {
var mandatoryClaimCBs = $(".mandatory-claim"); var mandatoryClaimCBs = $(".mandatory-claim");
var checkedMandatoryClaimCBs = $(".mandatory-claim:checked"); var checkedMandatoryClaimCBs = $(".mandatory-claim:checked");
if (checkedMandatoryClaimCBs.length == mandatoryClaimCBs.length) { if (checkedMandatoryClaimCBs.length == mandatoryClaimCBs.length) {
document.getElementById('consent').value = "approve"; if(ssoProtocol === "saml") {
document.getElementById('consent').value = "approve";
} else if(ssoProtocol === "oidc") {
document.getElementById('consent').value = "approveAlways";
}
document.getElementById("consentForm").submit(); document.getElementById("consentForm").submit();
} else { } else {
$("#modal_claim_validation").modal(); $("#modal_claim_validation").modal();
@ -32,4 +36,4 @@ $(document).ready(function () {
$("#consent_select_all").prop("checked", false); $("#consent_select_all").prop("checked", false);
} }
}); });
}); });

@ -27,12 +27,10 @@ import io.entgra.ui.request.interceptor.beans.AuthData;
import io.entgra.ui.request.interceptor.exceptions.LoginException; import io.entgra.ui.request.interceptor.exceptions.LoginException;
import io.entgra.ui.request.interceptor.util.HandlerConstants; import io.entgra.ui.request.interceptor.util.HandlerConstants;
import io.entgra.ui.request.interceptor.util.HandlerUtil; import io.entgra.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders; import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
@ -71,66 +69,31 @@ public class LoginHandler extends HttpServlet {
//setting session to expiry in 5 minutes //setting session to expiry in 5 minutes
httpSession.setMaxInactiveInterval(Math.toIntExact(HandlerConstants.TIMEOUT)); httpSession.setMaxInactiveInterval(Math.toIntExact(HandlerConstants.TIMEOUT));
HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl); JsonObject uiConfigJsonObject = HandlerUtil.getUIConfigAndPersistInSession(uiConfigUrl, gatewayUrl, httpSession, resp);
ProxyResponse uiConfigResponse = HandlerUtil.execute(uiConfigEndpoint);
String executorResponse = uiConfigResponse.getExecutorResponse();
if (!StringUtils.isEmpty(executorResponse) && executorResponse
.contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
log.error("Error occurred while getting UI configurations by invoking " + uiConfigUrl);
HandlerUtil.handleError(resp, uiConfigResponse);
return;
}
String uiConfig = uiConfigResponse.getData();
if (uiConfig == null){
log.error("UI config retrieval is failed, and didn't find UI configuration for App manager.");
HandlerUtil.handleError(resp, null);
return;
}
JsonParser jsonParser = new JsonParser();
JsonElement uiConfigJsonElement = jsonParser.parse(uiConfigResponse.getData());
JsonObject uiConfigJsonObject = null;
if (uiConfigJsonElement.isJsonObject()) {
uiConfigJsonObject = uiConfigJsonElement.getAsJsonObject();
httpSession.setAttribute(HandlerConstants.UI_CONFIG_KEY, uiConfigJsonObject);
httpSession.setAttribute(HandlerConstants.PLATFORM, gatewayUrl);
}
if (uiConfigJsonObject == null) {
log.error(
"Either UI config json element is not an json object or converting rom json element to json object is failed.");
HandlerUtil.handleError(resp, null);
return;
}
boolean isSsoEnable = uiConfigJsonObject.get("isSsoEnable").getAsBoolean();
JsonArray tags = uiConfigJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray(); JsonArray tags = uiConfigJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray();
JsonArray scopes = uiConfigJsonObject.get("scopes").getAsJsonArray(); JsonArray scopes = uiConfigJsonObject.get("scopes").getAsJsonArray();
if (isSsoEnable) { HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
log.debug("SSO is enabled"); apiRegEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + Base64.getEncoder()
} else { .encodeToString((username + HandlerConstants.COLON + password).getBytes()));
// default login apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT); apiRegEndpoint.setEntity(HandlerUtil.constructAppRegPayload(tags, HandlerConstants.PUBLISHER_APPLICATION_NAME, username, password));
apiRegEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + Base64.getEncoder()
.encodeToString((username + HandlerConstants.COLON + password).getBytes()));
apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
apiRegEndpoint.setEntity(constructAppRegPayload(tags));
ProxyResponse clientAppResponse = HandlerUtil.execute(apiRegEndpoint); ProxyResponse clientAppResponse = HandlerUtil.execute(apiRegEndpoint);
if (clientAppResponse.getCode() == HttpStatus.SC_UNAUTHORIZED){ if (clientAppResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
HandlerUtil.handleError(resp, clientAppResponse); HandlerUtil.handleError(resp, clientAppResponse);
return; return;
} }
if (clientAppResponse.getCode() == HttpStatus.SC_CREATED && getTokenAndPersistInSession(req, resp, if (clientAppResponse.getCode() == HttpStatus.SC_CREATED && getTokenAndPersistInSession(req, resp,
clientAppResponse.getData(), scopes)) { clientAppResponse.getData(), scopes)) {
ProxyResponse proxyResponse = new ProxyResponse(); ProxyResponse proxyResponse = new ProxyResponse();
proxyResponse.setCode(HttpStatus.SC_OK); proxyResponse.setCode(HttpStatus.SC_OK);
HandlerUtil.handleSuccess(resp, proxyResponse); HandlerUtil.handleSuccess(resp, proxyResponse);
return; return;
}
HandlerUtil.handleError(resp, null);
} }
HandlerUtil.handleError(resp, null);
} catch (IOException e) { } catch (IOException e) {
log.error("Error occurred while sending the response into the socket. ", e); log.error("Error occurred while sending the response into the socket. ", e);
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
@ -141,6 +104,7 @@ public class LoginHandler extends HttpServlet {
} }
/*** /***
* Generates token from token endpoint and persists them inside the session
* *
* @param req - {@link HttpServletRequest} * @param req - {@link HttpServletRequest}
* @param clientAppResult - clientAppResult * @param clientAppResult - clientAppResult
@ -148,7 +112,7 @@ public class LoginHandler extends HttpServlet {
* @throws LoginException - login exception throws when getting token result * @throws LoginException - login exception throws when getting token result
*/ */
private boolean getTokenAndPersistInSession(HttpServletRequest req, HttpServletResponse resp, private boolean getTokenAndPersistInSession(HttpServletRequest req, HttpServletResponse resp,
String clientAppResult, JsonArray scopes) throws LoginException { String clientAppResult, JsonArray scopes) throws LoginException {
JsonParser jsonParser = new JsonParser(); JsonParser jsonParser = new JsonParser();
try { try {
JsonElement jClientAppResult = jsonParser.parse(clientAppResult); JsonElement jClientAppResult = jsonParser.parse(clientAppResult);
@ -167,7 +131,7 @@ public class LoginHandler extends HttpServlet {
return false; return false;
} }
String tokenResult = tokenResultResponse.getData(); String tokenResult = tokenResultResponse.getData();
if (tokenResult == null){ if (tokenResult == null) {
log.error("Invalid token response is received."); log.error("Invalid token response is received.");
HandlerUtil.handleError(resp, tokenResultResponse); HandlerUtil.handleError(resp, tokenResultResponse);
return false; return false;
@ -197,24 +161,6 @@ public class LoginHandler extends HttpServlet {
} }
} }
/***
*
* @param scopes - scope Json Array and it is retrieved by reading UI config.
* @return string value of the defined scopes
*/
private String getScopeString(JsonArray scopes) {
if (scopes != null && scopes.size() > 0) {
StringBuilder builder = new StringBuilder();
for (JsonElement scope : scopes) {
String tmpScope = scope.getAsString() + " ";
builder.append(tmpScope);
}
return builder.toString();
} else {
return null;
}
}
/*** /***
* *
* @param req - {@link HttpServletRequest} * @param req - {@link HttpServletRequest}
@ -239,22 +185,7 @@ public class LoginHandler extends HttpServlet {
} }
/*** /***
* * Generates tokens by invoking token endpoint
* @param tags - tags which are retrieved by reading app manager configuration
* @return {@link StringEntity} of the payload to create the client application
*/
private StringEntity constructAppRegPayload(JsonArray tags) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty(HandlerConstants.APP_NAME_KEY, HandlerConstants.PUBLISHER_APPLICATION_NAME);
jsonObject.addProperty(HandlerConstants.USERNAME, username);
jsonObject.addProperty(HandlerConstants.PASSWORD, password);
jsonObject.addProperty("isAllowedToAllDomains", "false");
jsonObject.add(HandlerConstants.TAGS_KEY, tags);
String payload = jsonObject.toString();
return new StringEntity(payload, ContentType.APPLICATION_JSON);
}
/***
* *
* @param encodedClientApp - Base64 encoded clientId:clientSecret. * @param encodedClientApp - Base64 encoded clientId:clientSecret.
* @param scopes - Scopes which are retrieved by reading application-mgt configuration * @param scopes - Scopes which are retrieved by reading application-mgt configuration
@ -265,7 +196,7 @@ public class LoginHandler extends HttpServlet {
HttpPost tokenEndpoint = new HttpPost(gatewayUrl + HandlerConstants.TOKEN_ENDPOINT); HttpPost tokenEndpoint = new HttpPost(gatewayUrl + HandlerConstants.TOKEN_ENDPOINT);
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedClientApp); tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedClientApp);
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString()); tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
String scopeString = getScopeString(scopes); String scopeString = HandlerUtil.getScopeString(scopes);
if (scopeString != null) { if (scopeString != null) {
scopeString = scopeString.trim(); scopeString = scopeString.trim();
@ -274,7 +205,8 @@ public class LoginHandler extends HttpServlet {
} }
StringEntity tokenEPPayload = new StringEntity( StringEntity tokenEPPayload = new StringEntity(
"grant_type=password&username=" + username + "&password=" + password + "&scope=" + scopeString, "grant_type=" + HandlerConstants.PASSWORD_GRANT_TYPE + "&username=" + username + "&password=" +
password + "&scope=" + scopeString,
ContentType.APPLICATION_FORM_URLENCODED); ContentType.APPLICATION_FORM_URLENCODED);
tokenEndpoint.setEntity(tokenEPPayload); tokenEndpoint.setEntity(tokenEPPayload);
return HandlerUtil.execute(tokenEndpoint); return HandlerUtil.execute(tokenEndpoint);

@ -0,0 +1,95 @@
/*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.ui.request.interceptor;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.entgra.ui.request.interceptor.beans.AuthData;
import io.entgra.ui.request.interceptor.util.HandlerConstants;
import io.entgra.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@MultipartConfig
@WebServlet("/ssoLoginCallback")
public class SsoLoginCallbackHandler extends HttpServlet {
private static final Log log = LogFactory.getLog(SsoLoginCallbackHandler.class);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String code = req.getParameter("code");
HttpSession session = req.getSession(false);
String scope = session.getAttribute("scope").toString();
String iotsCorePort = System.getProperty("iot.core.https.port");
if (HandlerConstants.HTTP_PROTOCOL.equals(req.getScheme())) {
iotsCorePort = System.getProperty("iot.core.http.port");
}
String gatewayUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty("iot.gateway.host")
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
String iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty("iot.core.host")
+ HandlerConstants.COLON + iotsCorePort;
HttpPost tokenEndpoint = new HttpPost(gatewayUrl + HandlerConstants.TOKEN_ENDPOINT);
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + session.getAttribute("encodedClientApp"));
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
String loginCallbackUrl = iotsCoreUrl + req.getContextPath() + HandlerConstants.SSO_LOGIN_CALLBACK;
StringEntity tokenEPPayload = new StringEntity(
"grant_type=" + HandlerConstants.CODE_GRANT_TYPE + "&code=" + code + "&state=&scope=" + scope +
"&redirect_uri=" + loginCallbackUrl,
ContentType.APPLICATION_FORM_URLENCODED);
tokenEndpoint.setEntity(tokenEPPayload);
ProxyResponse tokenResultResponse = HandlerUtil.execute(tokenEndpoint);
JsonParser jsonParser = new JsonParser();
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
if (jTokenResult.isJsonObject()) {
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
AuthData authData = new AuthData();
authData.setClientId(session.getAttribute("clientId").toString());
authData.setClientSecret(session.getAttribute("clientSecret").toString());
authData.setEncodedClientApp(session.getAttribute("encodedClientApp").toString());
authData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
authData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
authData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, authData);
resp.sendRedirect(session.getAttribute("redirectUrl").toString());
}
}
}

@ -0,0 +1,285 @@
/*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.ui.request.interceptor;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import io.entgra.ui.request.interceptor.util.HandlerConstants;
import io.entgra.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
import org.xml.sax.SAXException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
@MultipartConfig
@WebServlet("/ssoLogin")
public class SsoLoginHandler extends HttpServlet {
private static final Log log = LogFactory.getLog(SsoLoginHandler.class);
private static String adminUsername;
private static String adminPassword;
private static String gatewayUrl;
private static String iotsCoreUrl;
private static String encodedClientApp;
private static String applicationId;
private static String baseContextPath;
private JsonObject uiConfigJsonObject;
private HttpSession httpSession;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
dynamicClientRegistration(req, resp);
String clientId = httpSession.getAttribute("clientId").toString();
JsonArray scopesSsoJson = uiConfigJsonObject.get("scopes").getAsJsonArray();
String scopesSsoString = HandlerUtil.getScopeString(scopesSsoJson);
String loginCallbackUrl = iotsCoreUrl + baseContextPath + HandlerConstants.SSO_LOGIN_CALLBACK;
resp.sendRedirect(iotsCoreUrl + HandlerConstants.AUTHORIZATION_ENDPOINT +
"?response_type=code" +
"&client_id=" + clientId +
"&state=" +
"&scope=openid " + scopesSsoString +
"&redirect_uri=" + loginCallbackUrl);
}
/***
* Handles DCR and updates grant types of the application
* before redirecting to the authorization endpoint.
*
* @param req {@link HttpServletRequest}
* @param resp {@link HttpServletResponse}
*/
private void dynamicClientRegistration(HttpServletRequest req, HttpServletResponse resp) {
try {
File userMgtConf = new File("conf/user-mgt.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(userMgtConf);
adminUsername = doc.getElementsByTagName("UserName").item(0).getTextContent();
adminPassword = doc.getElementsByTagName("Password").item(0).getTextContent();
baseContextPath = req.getContextPath();
String applicationName = baseContextPath.substring(1, baseContextPath.indexOf("-ui-request-handler"));
String iotsCorePort = System.getProperty("iot.core.https.port");
if (HandlerConstants.HTTP_PROTOCOL.equals(req.getScheme())) {
iotsCorePort = System.getProperty("iot.core.http.port");
}
gatewayUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty("iot.gateway.host")
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty("iot.core.host")
+ HandlerConstants.COLON + iotsCorePort;
String uiConfigUrl = iotsCoreUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
httpSession = req.getSession(false);
if (httpSession != null) {
httpSession.invalidate();
}
httpSession = req.getSession(true);
uiConfigJsonObject = HandlerUtil.getUIConfigAndPersistInSession(uiConfigUrl, gatewayUrl, httpSession, resp);
JsonArray tags = uiConfigJsonObject.get("appRegistration").getAsJsonObject().get("tags").getAsJsonArray();
JsonArray scopes = uiConfigJsonObject.get("scopes").getAsJsonArray();
// Register the client application
HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
String encodedAdminCredentials = Base64.getEncoder()
.encodeToString((adminUsername + HandlerConstants.COLON + adminPassword).getBytes());
apiRegEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC +
encodedAdminCredentials);
apiRegEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
apiRegEndpoint.setEntity(HandlerUtil.constructAppRegPayload(tags, applicationName, adminUsername, adminPassword));
ProxyResponse clientAppResponse = HandlerUtil.execute(apiRegEndpoint);
if (clientAppResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
HandlerUtil.handleError(resp, clientAppResponse);
}
if (clientAppResponse.getCode() == HttpStatus.SC_CREATED) {
JsonParser jsonParser = new JsonParser();
JsonElement jClientAppResult = jsonParser.parse(clientAppResponse.getData());
if (jClientAppResult.isJsonObject()) {
JsonObject jClientAppResultAsJsonObject = jClientAppResult.getAsJsonObject();
String clientId = jClientAppResultAsJsonObject.get("client_id").getAsString();
String clientSecret = jClientAppResultAsJsonObject.get("client_secret").getAsString();
encodedClientApp = Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes());
String redirectUrl = req.getParameter("redirect");
httpSession = req.getSession(false);
httpSession.setAttribute("clientId", clientId);
httpSession.setAttribute("clientSecret", clientSecret);
httpSession.setAttribute("encodedClientApp", encodedClientApp);
httpSession.setAttribute("scope", HandlerUtil.getScopeString(scopes));
httpSession.setAttribute("redirectUrl", redirectUrl);
}
}
// Get the details of the registered application
String getApplicationEndpointUrl = iotsCoreUrl + HandlerConstants.APIM_APPLICATIONS_ENDPOINT +
"?query=" + applicationName;
HttpGet getApplicationEndpoint = new HttpGet(getApplicationEndpointUrl);
getApplicationEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER +
getAccessToken(resp, encodedClientApp));
ProxyResponse getApplicationResponse = HandlerUtil.execute(getApplicationEndpoint);
if (getApplicationResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
HandlerUtil.handleError(resp, getApplicationResponse);
return;
}
if (getApplicationResponse.getCode() == HttpStatus.SC_OK) {
JsonParser jsonParser = new JsonParser();
JsonElement jAppResult = jsonParser.parse(getApplicationResponse.getData());
if (jAppResult.isJsonObject()) {
JsonObject jClientAppResultAsJsonObject = jAppResult.getAsJsonObject();
JsonArray appList = jClientAppResultAsJsonObject.getAsJsonArray("list");
JsonObject app;
for (JsonElement appJson : appList) {
app = appJson.getAsJsonObject();
if (app.get("name").getAsString().equals(applicationName)) {
applicationId = app.get("applicationId").getAsString();
break;
}
}
}
}
// Update the grant types of the application
String url = iotsCoreUrl + HandlerConstants.APIM_APPLICATIONS_ENDPOINT + applicationId + "/keys/PRODUCTION";
HttpPut updateApplicationGrantTypesEndpoint = new HttpPut(url);
updateApplicationGrantTypesEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER +
getAccessToken(resp, encodedClientApp));
updateApplicationGrantTypesEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
updateApplicationGrantTypesEndpoint.setEntity(constructAppGrantTypeUpdatePayload());
ProxyResponse updateApplicationGrantTypesEndpointResponse = HandlerUtil.execute(updateApplicationGrantTypesEndpoint);
if (updateApplicationGrantTypesEndpointResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
HandlerUtil.handleError(resp, updateApplicationGrantTypesEndpointResponse);
return;
}
if (updateApplicationGrantTypesEndpointResponse.getCode() == HttpStatus.SC_OK) {
return;
}
HandlerUtil.handleError(resp, null);
} catch (IOException e) {
log.error("Error occurred while sending the response into the socket. ", e);
} catch (JsonSyntaxException e) {
log.error("Error occurred while parsing the response. ", e);
} catch (ParserConfigurationException | SAXException e) {
log.error("Error while parsing xml file.", e);
}
}
/***
* Generates payload for application grant_type update payload
*
* @return {@link StringEntity} of the payload to update application grant type
*/
private StringEntity constructAppGrantTypeUpdatePayload() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("supportedGrantTypes", new JSONArray(new Object[]{HandlerConstants.CODE_GRANT_TYPE,
HandlerConstants.REFRESH_TOKEN_GRANT_TYPE, HandlerConstants.PASSWORD_GRANT_TYPE}));
jsonObject.put(HandlerConstants.CALLBACK_URL_KEY, iotsCoreUrl + baseContextPath + HandlerConstants.SSO_LOGIN_CALLBACK);
String payload = jsonObject.toString();
return new StringEntity(payload, ContentType.APPLICATION_JSON);
}
/***
* Generates tokens using password grant_type by invoking token endpoint
*
* @param encodedClientApp - Base64 encoded clientId:clientSecret.
* @return Invoke token endpoint and return the response as string.
* @throws IOException IO exception throws if an error occurred when invoking token endpoint
*/
private ProxyResponse getTokenResult(String encodedClientApp) throws IOException {
HttpPost tokenEndpoint = new HttpPost(gatewayUrl + HandlerConstants.TOKEN_ENDPOINT);
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedClientApp);
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
StringEntity tokenEPPayload = new StringEntity(
"grant_type=" + HandlerConstants.PASSWORD_GRANT_TYPE + "&username=" + adminUsername + "&password=" + adminPassword +
"&scope=apim:api_view apim:api_create apim:api_publish apim:subscribe",
ContentType.APPLICATION_FORM_URLENCODED);
tokenEndpoint.setEntity(tokenEPPayload);
return HandlerUtil.execute(tokenEndpoint);
}
/***
* Retrieves and returns access token
*
* @param resp - Http Servlet Response
* @param encodedClientApp - Base64 encoded clientId:clientSecret.
* @return Returns access token
* @throws IOException IO exception throws if an error occurred when invoking token endpoint
*/
private String getAccessToken(HttpServletResponse resp, String encodedClientApp) throws IOException {
ProxyResponse tokenResultResponse = getTokenResult(encodedClientApp);
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
log.error("Error occurred while invoking the API to get token data.");
HandlerUtil.handleError(resp, tokenResultResponse);
}
String tokenResult = tokenResultResponse.getData();
if (tokenResult == null) {
log.error("Invalid token response is received.");
HandlerUtil.handleError(resp, tokenResultResponse);
}
JsonParser jsonParser = new JsonParser();
JsonElement jTokenResult = jsonParser.parse(tokenResult);
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
return jTokenResultAsJsonObject.get("access_token").getAsString();
}
}

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.ui.request.interceptor;
import io.entgra.ui.request.interceptor.util.HandlerConstants;
import io.entgra.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus;
import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Cookie;
import java.io.IOException;
@MultipartConfig
@WebServlet("/ssoLogout")
public class SsoLogoutHandler extends HttpServlet {
private static final Log log = LogFactory.getLog(SsoLogoutHandler.class);
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
for (String path : HandlerConstants.SSO_LOGOUT_COOKIE_PATHS) {
removeCookie(HandlerConstants.JSESSIONID_KEY, System.getProperty("iot.core.host"), path, resp);
}
removeCookie(HandlerConstants.COMMON_AUTH_ID_KEY, System.getProperty("iot.core.host"), "/", resp);
ProxyResponse proxyResponse = new ProxyResponse();
proxyResponse.setCode(HttpStatus.SC_OK);
HttpSession session = req.getSession(false);
if (session != null) {
session.invalidate();
}
try {
HandlerUtil.handleSuccess(resp, proxyResponse);
} catch (IOException e) {
log.error("Error occurred when processing logout request.", e);
}
}
private static void removeCookie(String cookieName, String domain,
String path, HttpServletResponse response) {
Cookie cookie = new Cookie(cookieName, "");
cookie.setPath(path);
cookie.setDomain(domain);
cookie.setValue(null);
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}

@ -24,7 +24,10 @@ public class HandlerConstants {
public static final String UI_CONFIG_ENDPOINT = "/api/device-mgt-config/v1.0/configurations/ui-config"; public static final String UI_CONFIG_ENDPOINT = "/api/device-mgt-config/v1.0/configurations/ui-config";
public static final String TOKEN_ENDPOINT = "/token"; public static final String TOKEN_ENDPOINT = "/token";
public static final String INTROSPECT_ENDPOINT = "/oauth2/introspect"; public static final String INTROSPECT_ENDPOINT = "/oauth2/introspect";
public static final String AUTHORIZATION_ENDPOINT = "/oauth2/authorize";
public static final String APIM_APPLICATIONS_ENDPOINT = "/api/am/store/v0.12/applications/";
public static final String LOGIN_PAGE = "/login"; public static final String LOGIN_PAGE = "/login";
public static final String SSO_LOGIN_CALLBACK = "/ssoLoginCallback";
public static final String BASIC = "Basic "; public static final String BASIC = "Basic ";
public static final String BEARER = "Bearer "; public static final String BEARER = "Bearer ";
public static final String TAGS_KEY = "tags"; public static final String TAGS_KEY = "tags";
@ -32,6 +35,10 @@ public class HandlerConstants {
public static final String SESSION_AUTH_DATA_KEY = "authInfo"; public static final String SESSION_AUTH_DATA_KEY = "authInfo";
public static final String SESSION_DEFAULT_AUTH_DATA_KEY = "defaultAuthInfo"; public static final String SESSION_DEFAULT_AUTH_DATA_KEY = "defaultAuthInfo";
public static final String UI_CONFIG_KEY = "ui-config"; public static final String UI_CONFIG_KEY = "ui-config";
public static final String CALLBACK_URL_KEY = "callbackUrl";
public static final String IS_ALLOWED_TO_ALL_DOMAINS_KEY = "isAllowedToAllDomains";
public static final String JSESSIONID_KEY = "JSESSIONID";
public static final String COMMON_AUTH_ID_KEY = "commonAuthId";
public static final String PLATFORM = "platform"; public static final String PLATFORM = "platform";
public static final String USERNAME = "username"; public static final String USERNAME = "username";
public static final String PASSWORD = "password"; public static final String PASSWORD = "password";
@ -40,6 +47,11 @@ public class HandlerConstants {
public static final String TOKEN_IS_EXPIRED = "ACCESS_TOKEN_IS_EXPIRED"; public static final String TOKEN_IS_EXPIRED = "ACCESS_TOKEN_IS_EXPIRED";
public static final String REPORTS = "Reports"; public static final String REPORTS = "Reports";
public static final String APP_NAME = "App-Name"; public static final String APP_NAME = "App-Name";
public static final String[] SSO_LOGOUT_COOKIE_PATHS = new String[]{"/", "/entgra-ui-request-handler",
"/store-ui-request-handler", "/publisher-ui-request-handler", "/mdm-reports-ui-request-handler", "/devicemgt"};
public static final String CODE_GRANT_TYPE = "authorization_code";
public static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
public static final String PASSWORD_GRANT_TYPE = "password";
public static final String SCHEME_SEPARATOR = "://"; public static final String SCHEME_SEPARATOR = "://";
public static final String COLON = ":"; public static final String COLON = ":";

@ -19,15 +19,21 @@
package io.entgra.ui.request.interceptor.util; package io.entgra.ui.request.interceptor.util;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.json.JSONException; import org.json.JSONException;
@ -36,6 +42,7 @@ import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -113,37 +120,37 @@ public class HandlerUtil {
* @param statusCode Provide status code, e.g:- 400, 401, 500 etc * @param statusCode Provide status code, e.g:- 400, 401, 500 etc
* @return relative status code key for given status code. * @return relative status code key for given status code.
*/ */
public static String getStatusKey (int statusCode){ public static String getStatusKey(int statusCode) {
String statusCodeKey; String statusCodeKey;
switch (statusCode) { switch (statusCode) {
case HttpStatus.SC_INTERNAL_SERVER_ERROR: case HttpStatus.SC_INTERNAL_SERVER_ERROR:
statusCodeKey = "internalServerError"; statusCodeKey = "internalServerError";
break; break;
case HttpStatus.SC_BAD_REQUEST: case HttpStatus.SC_BAD_REQUEST:
statusCodeKey = "badRequest"; statusCodeKey = "badRequest";
break; break;
case HttpStatus.SC_UNAUTHORIZED: case HttpStatus.SC_UNAUTHORIZED:
statusCodeKey = "unauthorized"; statusCodeKey = "unauthorized";
break; break;
case HttpStatus.SC_FORBIDDEN: case HttpStatus.SC_FORBIDDEN:
statusCodeKey = "forbidden"; statusCodeKey = "forbidden";
break; break;
case HttpStatus.SC_NOT_FOUND: case HttpStatus.SC_NOT_FOUND:
statusCodeKey = "notFound"; statusCodeKey = "notFound";
break; break;
case HttpStatus.SC_METHOD_NOT_ALLOWED: case HttpStatus.SC_METHOD_NOT_ALLOWED:
statusCodeKey = "methodNotAllowed"; statusCodeKey = "methodNotAllowed";
break; break;
case HttpStatus.SC_NOT_ACCEPTABLE: case HttpStatus.SC_NOT_ACCEPTABLE:
statusCodeKey = "notAcceptable"; statusCodeKey = "notAcceptable";
break; break;
case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE: case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE:
statusCodeKey = "unsupportedMediaType"; statusCodeKey = "unsupportedMediaType";
break; break;
default: default:
statusCodeKey = "defaultPage"; statusCodeKey = "defaultPage";
break; break;
} }
return statusCodeKey; return statusCodeKey;
} }
@ -156,7 +163,7 @@ public class HandlerUtil {
*/ */
public static void handleError(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException { public static void handleError(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
Gson gson = new Gson(); Gson gson = new Gson();
if (proxyResponse == null){ if (proxyResponse == null) {
proxyResponse = new ProxyResponse(); proxyResponse = new ProxyResponse();
proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil
@ -178,7 +185,7 @@ public class HandlerUtil {
* Return Success Response. * Return Success Response.
*/ */
public static void handleSuccess(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException { public static void handleSuccess(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
if (proxyResponse == null){ if (proxyResponse == null) {
handleError(resp, null); handleError(resp, null);
return; return;
} }
@ -188,7 +195,7 @@ public class HandlerUtil {
JSONObject response = new JSONObject(); JSONObject response = new JSONObject();
String responseData = proxyResponse.getData(); String responseData = proxyResponse.getData();
if (!StringUtils.isEmpty(responseData)){ if (!StringUtils.isEmpty(responseData)) {
try { try {
JSONObject responseDataJsonObj = new JSONObject(responseData); JSONObject responseDataJsonObj = new JSONObject(responseData);
response.put("data", responseDataJsonObj); response.put("data", responseDataJsonObj);
@ -205,6 +212,7 @@ public class HandlerUtil {
/** /**
* Get gateway port according to request received scheme * Get gateway port according to request received scheme
*
* @param scheme https or https * @param scheme https or https
* @return {@link String} gateway port * @return {@link String} gateway port
*/ */
@ -218,6 +226,7 @@ public class HandlerUtil {
/** /**
* Get core port according to request received scheme * Get core port according to request received scheme
*
* @param scheme https or https * @param scheme https or https
* @return {@link String} gateway port * @return {@link String} gateway port
*/ */
@ -231,6 +240,7 @@ public class HandlerUtil {
/** /**
* Retrieve Http client based on hostname verification. * Retrieve Http client based on hostname verification.
*
* @return {@link CloseableHttpClient} http client * @return {@link CloseableHttpClient} http client
*/ */
public static CloseableHttpClient getHttpClient() { public static CloseableHttpClient getHttpClient() {
@ -273,4 +283,83 @@ public class HandlerUtil {
} }
return urlBuilder.toString(); return urlBuilder.toString();
} }
/***
* Constructs the application registration payload for DCR.
*
* @param tags - tags which are retrieved by reading app manager configuration
* @param username - username provided from login form or admin username
* @param password - password provided from login form or admin password
* @return {@link StringEntity} of the payload to create the client application
*/
public static StringEntity constructAppRegPayload(JsonArray tags, String appName, String username, String password) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty(HandlerConstants.APP_NAME_KEY, appName);
jsonObject.addProperty(HandlerConstants.USERNAME, username);
jsonObject.addProperty(HandlerConstants.PASSWORD, password);
jsonObject.addProperty(HandlerConstants.IS_ALLOWED_TO_ALL_DOMAINS_KEY, "false");
jsonObject.add(HandlerConstants.TAGS_KEY, tags);
String payload = jsonObject.toString();
return new StringEntity(payload, ContentType.APPLICATION_JSON);
}
/***
* Retrieves UI configuration and returns as Json.
*
* @param uiConfigUrl - UI configurations endpoint URL
* @param gatewayUrl - gateway endpoint URL
* @param httpSession - current active HttpSession
* @param resp - HttpServletResponse
* @return {@link JsonObject} of UI configurations
*/
public static JsonObject getUIConfigAndPersistInSession(String uiConfigUrl, String gatewayUrl, HttpSession httpSession,
HttpServletResponse resp) throws IOException {
HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl);
ProxyResponse uiConfigResponse = HandlerUtil.execute(uiConfigEndpoint);
String executorResponse = uiConfigResponse.getExecutorResponse();
if (!StringUtils.isEmpty(executorResponse) && executorResponse
.contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
log.error("Error occurred while getting UI configurations by invoking " + uiConfigUrl);
HandlerUtil.handleError(resp, uiConfigResponse);
}
if (uiConfigResponse.getData() == null) {
log.error("UI config retrieval is failed, and didn't find UI configuration for App manager.");
HandlerUtil.handleError(resp, null);
}
JsonParser jsonParser = new JsonParser();
JsonElement uiConfigJsonElement = jsonParser.parse(uiConfigResponse.getData());
JsonObject uiConfigJsonObject = null;
if (uiConfigJsonElement.isJsonObject()) {
uiConfigJsonObject = uiConfigJsonElement.getAsJsonObject();
if (uiConfigJsonObject == null) {
log.error(
"Either UI config json element is not an json object or converting rom json element to json object is failed.");
HandlerUtil.handleError(resp, null);
}
httpSession.setAttribute(HandlerConstants.UI_CONFIG_KEY, uiConfigJsonObject);
httpSession.setAttribute(HandlerConstants.PLATFORM, gatewayUrl);
}
return uiConfigJsonObject;
}
/***
* Converts scopes from JsonArray to string with space separated values.
*
* @param scopes - scope Json Array and it is retrieved by reading UI config.
* @return string value of the defined scopes
*/
public static String getScopeString(JsonArray scopes) {
if (scopes != null && scopes.size() > 0) {
StringBuilder builder = new StringBuilder();
for (JsonElement scope : scopes) {
String tmpScope = scope.getAsString() + " ";
builder.append(tmpScope);
}
return builder.toString();
} else {
return null;
}
}
} }

@ -19,7 +19,7 @@
<UIConfiguration> <UIConfiguration>
<EnableOAuth>true</EnableOAuth> <EnableOAuth>true</EnableOAuth>
<EnableSSO>false</EnableSSO> <EnableSSO>true</EnableSSO>
<AppRegistration> <AppRegistration>
<Tags> <Tags>
<Tag>application_management</Tag> <Tag>application_management</Tag>

Loading…
Cancel
Save