#726 : Resolving cannot log into devicemgt app when tenant is not loaded in API Manager

This commit is contained in:
Rasika Perera 2017-05-03 19:59:17 +05:30
parent d3b322ed4e
commit 2831bfaf2c
14 changed files with 253 additions and 28 deletions

View File

@ -26,6 +26,12 @@ import org.wso2.carbon.apimgt.application.extension.exception.APIManagerExceptio
*/ */
public interface APIManagementProviderService { public interface APIManagementProviderService {
/**
* Check whether the tier is loaded for the tenant.
* @return
*/
boolean isTierLoaded();
/** /**
* Generate and retreive application keys. if the application does exist then * Generate and retreive application keys. if the application does exist then
* create it and subscribe to apis that are grouped with the tags. * create it and subscribe to apis that are grouped with the tags.

View File

@ -45,8 +45,22 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
private static final String CONTENT_TYPE = "application/json"; private static final String CONTENT_TYPE = "application/json";
private static final int MAX_API_PER_TAG = 200; private static final int MAX_API_PER_TAG = 200;
private static final String APP_TIER_TYPE = "application"; private static final String APP_TIER_TYPE = "application";
private static final Map<String, String> tiersMap = new HashMap<>();
private static final int MAX_ATTEMPTS = 20; public boolean isTierLoaded() {
StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
.getStoreClient();
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext()
.getTenantDomain();
try {
storeClient.getIndividualTier().tiersTierLevelTierNameGet(ApiApplicationConstants.DEFAULT_TIER,
APP_TIER_TYPE,
tenantDomain, CONTENT_TYPE, null, null);
return true;
} catch (FeignException e) {
return false;
}
}
@Override @Override
public void removeAPIApplication(String applicationName, String username) throws APIManagerException { public void removeAPIApplication(String applicationName, String username) throws APIManagerException {
@ -72,31 +86,8 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
throws APIManagerException { throws APIManagerException {
StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService() StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
.getStoreClient(); .getStoreClient();
//This is a fix to avoid race condition and trying to load tenant related tiers before invocation.
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext() String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext()
.getTenantDomain(); .getTenantDomain();
String tiersLoadedForTenant = tiersMap.get(tenantDomain);
if (tiersLoadedForTenant == null) {
boolean tierLoaded = false;
int attempts = 0;
do {
try {
storeClient.getIndividualTier()
.tiersTierLevelTierNameGet(ApiApplicationConstants.DEFAULT_TIER, APP_TIER_TYPE,
tenantDomain, CONTENT_TYPE, null, null);
tiersMap.put(tenantDomain, "exist");
tierLoaded = true;
} catch (FeignException e) {
attempts++;
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
log.warn("Interrupted the waiting for tier availability.");
}
}
} while ((!tierLoaded) && attempts < MAX_ATTEMPTS);
}
ApplicationList applicationList = storeClient.getApplications() ApplicationList applicationList = storeClient.getApplications()
.applicationsGet("", applicationName, 1, 0, CONTENT_TYPE, null); .applicationsGet("", applicationName, 1, 0, CONTENT_TYPE, null);

View File

@ -19,7 +19,9 @@ package org.wso2.carbon.apimgt.integration.client.store;
import feign.Feign; import feign.Feign;
import feign.Logger; import feign.Logger;
import feign.Request;
import feign.RequestInterceptor; import feign.RequestInterceptor;
import feign.Retryer;
import feign.gson.GsonDecoder; import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder; import feign.gson.GsonEncoder;
import feign.slf4j.Slf4jLogger; import feign.slf4j.Slf4jLogger;
@ -28,6 +30,8 @@ import org.wso2.carbon.apimgt.integration.client.configs.APIMConfigReader;
import org.wso2.carbon.apimgt.integration.generated.client.store.api.*; import org.wso2.carbon.apimgt.integration.generated.client.store.api.*;
import org.wso2.carbon.core.util.Utils; import org.wso2.carbon.core.util.Utils;
import java.util.concurrent.TimeUnit;
/** /**
* API Store client, created using swagger gen. * API Store client, created using swagger gen.
*/ */
@ -62,8 +66,10 @@ public class StoreClient {
individualSubscription = builder.target(SubscriptionIndividualApi.class, basePath); individualSubscription = builder.target(SubscriptionIndividualApi.class, basePath);
subscriptionMultitpleApi = builder.target(SubscriptionMultitpleApi.class, basePath); subscriptionMultitpleApi = builder.target(SubscriptionMultitpleApi.class, basePath);
tags = builder.target(TagCollectionApi.class, basePath); tags = builder.target(TagCollectionApi.class, basePath);
tiers = builder.target(ThrottlingTierCollectionApi.class, basePath);
individualTier = builder.target(ThrottlingTierIndividualApi.class, basePath); individualTier = builder.target(ThrottlingTierIndividualApi.class, basePath);
tiers = builder.retryer(new Retryer.Default(100L, TimeUnit.SECONDS.toMillis(1L), 1))
.options(new Request.Options(10000, 5000))
.target(ThrottlingTierCollectionApi.class, basePath);
} }

View File

@ -176,6 +176,27 @@ if (uriMatcher.match("/{context}/api/user/authenticate")) {
} }
} else if (uriMatcher.match("/{context}/api/user/all")) { } else if (uriMatcher.match("/{context}/api/user/all")) {
result = userModule.getUsers(); result = userModule.getUsers();
} else if (uriMatcher.match("/{context}/api/user/environment-loaded")) {
try {
var carbonUser = session.get(constants.USER_SESSION_KEY);
if (!carbonUser) {
response.sendRedirect("/devicemgt/login?#login-required");
exit();
}
utility.startTenantFlow(carbonUser);
var APIManagementProviderService = utility.getAPIManagementProviderService();
var isLoaded = APIManagementProviderService.isTierLoaded();
result = {"isLoaded": isLoaded};
if (isLoaded) {
var samlToken = session.get(constants.SAML_TOKEN_KEY);
if (samlToken) {
apiWrapperUtil.setupTokenPairByJWTGrantType(carbonUser.username + '@' + carbonUser.domain, samlToken);
}
}
response.contentType = 'application/json';
} finally {
utility.endTenantFlow();
}
} }
// returning the result. // returning the result.

View File

@ -11,7 +11,7 @@
"login": { "login": {
"onSuccess": { "onSuccess": {
"script": "/app/modules/login.js", "script": "/app/modules/login.js",
"page": "cdmf.page.dashboard" "page": "cdmf.page.processing"
}, },
"onFail": { "onFail": {
"script": "/app/modules/login.js", "script": "/app/modules/login.js",

View File

@ -0,0 +1,57 @@
{{!-- Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file except
in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the
specific language governing permissions and limitations
under the License. --}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{defineZone "favicon"}}
<title>
{{defineZone "title"}}
</title>
{{defineZone "topLibCss"}}
{{defineZone "topCss"}}
{{defineZone "topJs"}}
</head>
<body>
<!--modal-->
<div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="modalDemo">
<div class="modal-dialog" role="document">
<div class="modal-content clearfix">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fw fw-cancel"></i></button>
</div>
<div class="modal-body add-margin-top-2x add-margin-bottom-2x">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!--modal-->
{{defineZone "content"}}
{{defineZone "bottomModalContent"}}
{{defineZone "bottomLibJs"}}
{{defineZone "bottomJs"}}
</body>
</html>

View File

@ -81,3 +81,6 @@ var CACHED_CREDENTIALS = "tenantBasedCredentials";
var CACHED_CREDENTIALS_FOR_WEBSOCKET_APP = "tenantBasedWebSocketClientCredentials"; var CACHED_CREDENTIALS_FOR_WEBSOCKET_APP = "tenantBasedWebSocketClientCredentials";
var ALLOWED_SCOPES = "scopes"; var ALLOWED_SCOPES = "scopes";
var SAML_TOKEN_KEY = "samlToken";
var SKIP_WELCOME_SCREEN ="skipWelcomeScreen";

View File

@ -25,6 +25,19 @@ var onFail;
onSuccess = function (context) { onSuccess = function (context) {
var utility = require("/app/modules/utility.js").utility; var utility = require("/app/modules/utility.js").utility;
var apiWrapperUtil = require("/app/modules/oauth/token-handlers.js")["handlers"]; var apiWrapperUtil = require("/app/modules/oauth/token-handlers.js")["handlers"];
try {
utility.startTenantFlow(context.user);
var APIManagementProviderService = utility.getAPIManagementProviderService();
var isLoaded = APIManagementProviderService.isTierLoaded();
if(!isLoaded && context.input.samlToken) {
session.put(constants.SKIP_WELCOME_SCREEN, false);
session.put(constants.SAML_TOKEN_KEY, context.input.samlToken);
return;
}
} finally {
utility.endTenantFlow();
}
session.put(constants.SKIP_WELCOME_SCREEN, true);
if (context.input.samlToken) { if (context.input.samlToken) {
//apiWrapperUtil.setupTokenPairBySamlGrantType(context.user.username + '@' + context.user.domain, context.input.samlToken); //apiWrapperUtil.setupTokenPairBySamlGrantType(context.user.username + '@' + context.user.domain, context.input.samlToken);
/** /**

View File

@ -53,6 +53,10 @@ utility = function () {
return getOsgiService('org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService'); return getOsgiService('org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService');
}; };
publicMethods.getAPIManagementProviderService = function () {
return getOsgiService('org.wso2.carbon.apimgt.application.extension.APIManagementProviderService');
};
publicMethods.getUserManagementService = function () { publicMethods.getUserManagementService = function () {
return getOsgiService("org.wso2.carbon.device.mgt.user.core.UserManager"); return getOsgiService("org.wso2.carbon.device.mgt.user.core.UserManager");
}; };

View File

@ -16,7 +16,7 @@
* under the License. * under the License.
*/ */
function onRequest() { function onRequest(context) {
var constants = require("/app/modules/constants.js"); var constants = require("/app/modules/constants.js");
var userModule = require("/app/modules/business-controllers/user.js")["userModule"]; var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"];
@ -24,6 +24,11 @@ function onRequest() {
var groupModule = require("/app/modules/business-controllers/group.js")["groupModule"]; var groupModule = require("/app/modules/business-controllers/group.js")["groupModule"];
var policyModule = require("/app/modules/business-controllers/policy.js")["policyModule"]; var policyModule = require("/app/modules/business-controllers/policy.js")["policyModule"];
if(!session.get(constants["TOKEN_PAIR"])){
response.sendRedirect(context.app.context + "/welcome");
return;
}
var user = session.get(constants["USER_SESSION_KEY"]); var user = session.get(constants["USER_SESSION_KEY"]);
var permissions = userModule.getUIPermissions(); var permissions = userModule.getUIPermissions();

View File

@ -0,0 +1,57 @@
{{!
Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file except
in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
}}
{{unit "cdmf.unit.ui.title" pageTitle="Home"}}
{{#zone "breadcrumbs"}}
<li>
<a href="{{@app.context}}/">
<i class="icon fw fw-home"></i>
</a>
</li>
{{/zone}}
{{#zone "content"}}
<div class="row">
<div class="col-md-12">
Loading...Please Wait
</div>
</div>
{{/zone}}
{{#zone "bottomJs"}}
<script type="text/javascript">
$('body').attr("data-toggle", "loading")
.attr("data-loading-style", "overlay")
.attr("data-loading-text", "SETTING UP YOUR ENVIRONMENT . . .");
$('[data-toggle="loading"]').loading('show');
</script>
{{js "/js/script.js"}}
{{/zone}}
{{#zone "topCss"}}
<style>
.loading[data-loading-style=overlay] .loading-bg{
background: #11375B;
opacity: 1;
filter: alpha(opacity=100);
}
.loading .loading-animation{
width : 200px;
}
</style>
{{/zone}}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function onRequest(context) {
var constants = require("/app/modules/constants.js");
var skipWelcomeScreen = session.get(constants.SKIP_WELCOME_SCREEN);
if (skipWelcomeScreen) {
response.sendRedirect(context.app.context + "/");
exit();
}
return {};
}

View File

@ -0,0 +1,5 @@
{
"version": "1.0.0",
"uri": "/welcome",
"layout": "cdmf.layout.loading"
}

View File

@ -0,0 +1,30 @@
var pollingCount = 24;
function poll() {
$.ajax({
url: context + "/api/user/environment-loaded",
type: "GET",
success: function (data) {
if (data.isLoaded) {
window.location = context + "/";
}
},
dataType: "json",
complete: setTimeout(function () {
pollingCount = pollingCount - 1;
if (pollingCount > 0) {
poll();
} else {
$(".loading-animation .logo").hide();
$(".loading-animation").prepend(
'<i class="fw fw-error fw-inverse fw-2x" style="float: left;"></i>');
$(".loading-animation p").css("width", "150%")
.html("Ops... it seems something went wrong.<br/> Refresh the page to retry!");
}
}, 5000),
timeout: 5000
});
}
$(document).ready(function () {
poll();
});