diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json
index 9264aac6d7..e953f2a4b1 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json
@@ -1,4 +1,5 @@
{
+ "appName": "publisher",
"theme": {
"logo": "https://entgra.io/assets/images/svg/logo.svg",
"primaryColor": "rgb(24, 144, 255)",
@@ -14,7 +15,10 @@
},
"loginUri": "/publisher-ui-request-handler/login",
"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": {
"default": {
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js
index 78a387b656..33332fc89e 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js
@@ -23,6 +23,7 @@ import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import axios from 'axios';
import { Layout, Spin, Result } from 'antd';
import ConfigContext from './components/ConfigContext';
+import { getUiConfig } from './services/utils/uiConfigHandler';
const { Content } = Layout;
const loadingView = (
@@ -161,12 +162,29 @@ class App extends React.Component {
const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
- if (lastURLSegment !== 'login') {
- window.location.href =
- window.location.origin + `/publisher/login?redirect=${redirectUrl}`;
- } else {
- this.getAndroidEnterpriseToken(config);
- }
+ getUiConfig(config).then(uiConfig => {
+ if (uiConfig !== undefined) {
+ if (uiConfig.isSsoEnable) {
+ window.location =
+ 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 {
this.setState({
loading: false,
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/components/Logout/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/components/Logout/index.js
index f41e654bcc..0ecbb604fa 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/components/Logout/index.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/components/Logout/index.js
@@ -21,6 +21,7 @@ import { LogoutOutlined } from '@ant-design/icons';
import { notification, Menu } from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../../../components/ConfigContext';
+import { getUiConfig } from '../../../../services/utils/uiConfigHandler';
/*
This class for call the logout api by sending request
@@ -44,27 +45,38 @@ class Logout extends React.Component {
inValid: false,
});
- axios
- .post(window.location.origin + config.serverConfig.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 + '/publisher/login';
- }
- })
- .catch(function(error) {
- if (error.hasOwnProperty('response') && error.response.status === 400) {
- thisForm.setState({
- inValid: true,
- });
+ let logoutUri;
+ getUiConfig(config).then(uiConfig => {
+ if (uiConfig !== undefined) {
+ if (uiConfig.isSsoEnable) {
+ logoutUri = window.location.origin + config.serverConfig.ssoLogoutUri;
} else {
- notification.error({
- message: 'There was a problem',
- duration: 0,
- description: 'Error occurred while trying to logout.',
- });
+ logoutUri = window.location.origin + config.serverConfig.logoutUri;
}
- });
+ 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() {
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/uiConfigHandler.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/uiConfigHandler.js
new file mode 100644
index 0000000000..77fd691c37
--- /dev/null
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/uiConfigHandler.js
@@ -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.',
+ });
+ });
+};
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/public/conf/config.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/public/conf/config.json
index 4850da1d91..7e36b866c5 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/public/conf/config.json
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/public/conf/config.json
@@ -1,4 +1,5 @@
{
+ "appName": "store",
"theme": {
"type": "default",
"value": "lightBaseTheme",
@@ -17,7 +18,10 @@
},
"loginUri": "/store-ui-request-handler/login",
"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": {
"default": {
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js
index 6ade8a306d..e78a5983d8 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js
@@ -21,8 +21,9 @@ import 'antd/dist/antd.less';
import RouteWithSubRoutes from './components/RouteWithSubRoutes';
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import axios from 'axios';
-import { Layout, Spin, Result } from 'antd';
+import { Layout, Result, Spin } from 'antd';
import ConfigContext from './components/context/ConfigContext';
+import { getUiConfig } from './services/utils/uiConfigHandler';
const { Content } = Layout;
const loadingView = (
@@ -138,15 +139,32 @@ class App extends React.Component {
const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
- if (lastURLSegment !== 'login') {
- window.location.href =
- window.location.origin + `/store/login?redirect=${redirectUrl}`;
- } else {
- this.setState({
- loading: false,
- config: config,
- });
- }
+ getUiConfig(config).then(uiConfig => {
+ if (uiConfig !== undefined) {
+ if (uiConfig.isSsoEnable) {
+ window.location =
+ 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.setState({
+ loading: false,
+ config: config,
+ });
+ }
+ } else {
+ this.setState({
+ loading: false,
+ error: true,
+ });
+ }
+ });
} else {
this.setState({
loading: false,
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/scenes/Home/components/Logout/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/scenes/Home/components/Logout/index.js
index d2c5e106eb..84bc6c0c94 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/scenes/Home/components/Logout/index.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/scenes/Home/components/Logout/index.js
@@ -22,6 +22,7 @@ import { Menu } from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../../../components/context/ConfigContext';
import { handleApiError } from '../../../../services/utils/errorHandler';
+import { getUiConfig } from '../../../../services/utils/uiConfigHandler';
/*
This class for call the logout api by sending request
@@ -45,20 +46,34 @@ class Logout extends React.Component {
inValid: false,
});
- axios
- .post(window.location.origin + config.serverConfig.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 + '/store/login';
+ let logoutUri;
+ getUiConfig(config).then(uiConfig => {
+ if (uiConfig !== undefined) {
+ if (uiConfig.isSsoEnable) {
+ logoutUri = window.location.origin + config.serverConfig.ssoLogoutUri;
+ } else {
+ logoutUri = window.location.origin + config.serverConfig.logoutUri;
}
- })
- .catch(function(error) {
- handleApiError(
- error,
- 'Error occurred while trying to get your review.',
- );
- });
+ 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) {
+ handleApiError(error, 'Error occurred while trying to logout.');
+ });
+ } else {
+ this.setState({
+ loading: false,
+ error: true,
+ });
+ }
+ });
};
render() {
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/services/utils/uiConfigHandler.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/services/utils/uiConfigHandler.js
new file mode 100644
index 0000000000..77fd691c37
--- /dev/null
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/services/utils/uiConfigHandler.js
@@ -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.',
+ });
+ });
+};
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.hbs
index 56f05e6956..22869a4828 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.hbs
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.hbs
@@ -29,7 +29,7 @@
-
@@ -72,4 +72,4 @@
{{/zone}}
{{#zone "bottomJs"}}
{{js "js/script.js"}}
-{{/zone}}
\ No newline at end of file
+{{/zone}}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.js
index 346b81df46..e3e4224eda 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.js
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/consent-do.js
@@ -1,7 +1,21 @@
function onRequest(context) {
var Encode = Packages.org.owasp.encoder.Encode;
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 requestedClaims = [];
var singleMandatoryClaim = false;
@@ -36,6 +50,5 @@ function onRequest(context) {
viewModel.mandatoryClaims = mandatoryClaims;
viewModel.requestedClaims = requestedClaims;
viewModel.singleMandatoryClaim = singleMandatoryClaim;
- viewModel.sessionDataKey = Encode.forHtmlAttribute(request.getParameter("sessionDataKey"));
return viewModel;
-}
\ No newline at end of file
+}
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/public/js/script.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/public/js/script.js
index 8588c004a9..7f6fff8d8b 100644
--- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/public/js/script.js
+++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.sign-in.consent-do/public/js/script.js
@@ -1,9 +1,13 @@
-function approved() {
+function approved(ssoProtocol) {
var mandatoryClaimCBs = $(".mandatory-claim");
var checkedMandatoryClaimCBs = $(".mandatory-claim:checked");
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();
} else {
$("#modal_claim_validation").modal();
@@ -32,4 +36,4 @@ $(document).ready(function () {
$("#consent_select_all").prop("checked", false);
}
});
-});
\ No newline at end of file
+});
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
index 53faa63eda..3ef9d9d4a9 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
@@ -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.util.HandlerConstants;
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.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.entity.ContentType;
import org.apache.http.entity.StringEntity;
@@ -71,66 +69,31 @@ public class LoginHandler extends HttpServlet {
//setting session to expiry in 5 minutes
httpSession.setMaxInactiveInterval(Math.toIntExact(HandlerConstants.TIMEOUT));
- 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);
- return;
- }
+ JsonObject uiConfigJsonObject = HandlerUtil.getUIConfigAndPersistInSession(uiConfigUrl, gatewayUrl, httpSession, resp);
- 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 scopes = uiConfigJsonObject.get("scopes").getAsJsonArray();
- if (isSsoEnable) {
- log.debug("SSO is enabled");
- } else {
- // default login
- HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
- 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));
+ HttpPost apiRegEndpoint = new HttpPost(gatewayUrl + HandlerConstants.APP_REG_ENDPOINT);
+ 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(HandlerUtil.constructAppRegPayload(tags, HandlerConstants.PUBLISHER_APPLICATION_NAME, username, password));
- ProxyResponse clientAppResponse = HandlerUtil.execute(apiRegEndpoint);
+ ProxyResponse clientAppResponse = HandlerUtil.execute(apiRegEndpoint);
- if (clientAppResponse.getCode() == HttpStatus.SC_UNAUTHORIZED){
- HandlerUtil.handleError(resp, clientAppResponse);
- return;
- }
- if (clientAppResponse.getCode() == HttpStatus.SC_CREATED && getTokenAndPersistInSession(req, resp,
- clientAppResponse.getData(), scopes)) {
- ProxyResponse proxyResponse = new ProxyResponse();
- proxyResponse.setCode(HttpStatus.SC_OK);
- HandlerUtil.handleSuccess(resp, proxyResponse);
- return;
- }
- HandlerUtil.handleError(resp, null);
+ if (clientAppResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
+ HandlerUtil.handleError(resp, clientAppResponse);
+ return;
+ }
+ if (clientAppResponse.getCode() == HttpStatus.SC_CREATED && getTokenAndPersistInSession(req, resp,
+ clientAppResponse.getData(), scopes)) {
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_OK);
+ HandlerUtil.handleSuccess(resp, proxyResponse);
+ return;
}
+ HandlerUtil.handleError(resp, null);
} catch (IOException e) {
log.error("Error occurred while sending the response into the socket. ", 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 clientAppResult - clientAppResult
@@ -148,7 +112,7 @@ public class LoginHandler extends HttpServlet {
* @throws LoginException - login exception throws when getting token result
*/
private boolean getTokenAndPersistInSession(HttpServletRequest req, HttpServletResponse resp,
- String clientAppResult, JsonArray scopes) throws LoginException {
+ String clientAppResult, JsonArray scopes) throws LoginException {
JsonParser jsonParser = new JsonParser();
try {
JsonElement jClientAppResult = jsonParser.parse(clientAppResult);
@@ -167,7 +131,7 @@ public class LoginHandler extends HttpServlet {
return false;
}
String tokenResult = tokenResultResponse.getData();
- if (tokenResult == null){
+ if (tokenResult == null) {
log.error("Invalid token response is received.");
HandlerUtil.handleError(resp, tokenResultResponse);
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}
@@ -239,22 +185,7 @@ public class LoginHandler extends HttpServlet {
}
/***
- *
- * @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);
- }
-
- /***
+ * Generates tokens by invoking token endpoint
*
* @param encodedClientApp - Base64 encoded clientId:clientSecret.
* @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);
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC + encodedClientApp);
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
- String scopeString = getScopeString(scopes);
+ String scopeString = HandlerUtil.getScopeString(scopes);
if (scopeString != null) {
scopeString = scopeString.trim();
@@ -274,7 +205,8 @@ public class LoginHandler extends HttpServlet {
}
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);
tokenEndpoint.setEntity(tokenEPPayload);
return HandlerUtil.execute(tokenEndpoint);
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginCallbackHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginCallbackHandler.java
new file mode 100644
index 0000000000..3d18be2ab1
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginCallbackHandler.java
@@ -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());
+ }
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginHandler.java
new file mode 100644
index 0000000000..1ea7d030e1
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLoginHandler.java
@@ -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();
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLogoutHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLogoutHandler.java
new file mode 100644
index 0000000000..a3d8f0bcc0
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/SsoLogoutHandler.java
@@ -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);
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
index b691eaa315..8c0e79c2a6 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
@@ -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 TOKEN_ENDPOINT = "/token";
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 SSO_LOGIN_CALLBACK = "/ssoLoginCallback";
public static final String BASIC = "Basic ";
public static final String BEARER = "Bearer ";
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_DEFAULT_AUTH_DATA_KEY = "defaultAuthInfo";
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 USERNAME = "username";
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 REPORTS = "Reports";
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 COLON = ":";
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
index 592806f338..5c80a88eb0 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
@@ -19,15 +19,21 @@
package io.entgra.ui.request.interceptor.util;
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.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
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.HttpClients;
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.HttpServletResponse;
+import javax.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -113,37 +120,37 @@ public class HandlerUtil {
* @param statusCode Provide status code, e.g:- 400, 401, 500 etc
* @return relative status code key for given status code.
*/
- public static String getStatusKey (int statusCode){
+ public static String getStatusKey(int statusCode) {
String statusCodeKey;
switch (statusCode) {
- case HttpStatus.SC_INTERNAL_SERVER_ERROR:
- statusCodeKey = "internalServerError";
- break;
- case HttpStatus.SC_BAD_REQUEST:
- statusCodeKey = "badRequest";
- break;
- case HttpStatus.SC_UNAUTHORIZED:
- statusCodeKey = "unauthorized";
- break;
- case HttpStatus.SC_FORBIDDEN:
- statusCodeKey = "forbidden";
- break;
- case HttpStatus.SC_NOT_FOUND:
- statusCodeKey = "notFound";
- break;
- case HttpStatus.SC_METHOD_NOT_ALLOWED:
- statusCodeKey = "methodNotAllowed";
- break;
- case HttpStatus.SC_NOT_ACCEPTABLE:
- statusCodeKey = "notAcceptable";
- break;
- case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE:
- statusCodeKey = "unsupportedMediaType";
- break;
- default:
- statusCodeKey = "defaultPage";
- break;
+ case HttpStatus.SC_INTERNAL_SERVER_ERROR:
+ statusCodeKey = "internalServerError";
+ break;
+ case HttpStatus.SC_BAD_REQUEST:
+ statusCodeKey = "badRequest";
+ break;
+ case HttpStatus.SC_UNAUTHORIZED:
+ statusCodeKey = "unauthorized";
+ break;
+ case HttpStatus.SC_FORBIDDEN:
+ statusCodeKey = "forbidden";
+ break;
+ case HttpStatus.SC_NOT_FOUND:
+ statusCodeKey = "notFound";
+ break;
+ case HttpStatus.SC_METHOD_NOT_ALLOWED:
+ statusCodeKey = "methodNotAllowed";
+ break;
+ case HttpStatus.SC_NOT_ACCEPTABLE:
+ statusCodeKey = "notAcceptable";
+ break;
+ case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE:
+ statusCodeKey = "unsupportedMediaType";
+ break;
+ default:
+ statusCodeKey = "defaultPage";
+ break;
}
return statusCodeKey;
}
@@ -156,7 +163,7 @@ public class HandlerUtil {
*/
public static void handleError(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
Gson gson = new Gson();
- if (proxyResponse == null){
+ if (proxyResponse == null) {
proxyResponse = new ProxyResponse();
proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil
@@ -178,7 +185,7 @@ public class HandlerUtil {
* Return Success Response.
*/
public static void handleSuccess(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
- if (proxyResponse == null){
+ if (proxyResponse == null) {
handleError(resp, null);
return;
}
@@ -188,7 +195,7 @@ public class HandlerUtil {
JSONObject response = new JSONObject();
String responseData = proxyResponse.getData();
- if (!StringUtils.isEmpty(responseData)){
+ if (!StringUtils.isEmpty(responseData)) {
try {
JSONObject responseDataJsonObj = new JSONObject(responseData);
response.put("data", responseDataJsonObj);
@@ -205,6 +212,7 @@ public class HandlerUtil {
/**
* Get gateway port according to request received scheme
+ *
* @param scheme https or https
* @return {@link String} gateway port
*/
@@ -218,6 +226,7 @@ public class HandlerUtil {
/**
* Get core port according to request received scheme
+ *
* @param scheme https or https
* @return {@link String} gateway port
*/
@@ -231,6 +240,7 @@ public class HandlerUtil {
/**
* Retrieve Http client based on hostname verification.
+ *
* @return {@link CloseableHttpClient} http client
*/
public static CloseableHttpClient getHttpClient() {
@@ -273,4 +283,83 @@ public class HandlerUtil {
}
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;
+ }
+ }
}
diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml
index f079a3bb48..78858d50b6 100644
--- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml
+++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/mdm-ui-config.xml
@@ -19,7 +19,7 @@
true
- false
+ true
application_management