Implemented extended scope validator and improved webapp publisher to support Synapse

4.x.x
mharindu 9 years ago
parent ed1eb217ea
commit f2ac5c5cad

@ -26,11 +26,9 @@ import org.wso2.carbon.apimgt.api.model.*;
import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.webapp.publisher.config.APIResource; import org.wso2.carbon.apimgt.webapp.publisher.config.APIResource;
import org.wso2.carbon.apimgt.webapp.publisher.config.APIResourceConfiguration; import org.wso2.carbon.apimgt.webapp.publisher.config.APIResourceConfiguration;
import org.wso2.carbon.apimgt.webapp.publisher.internal.APIPublisherDataHolder; import org.wso2.carbon.apimgt.webapp.publisher.config.WebappPublisherConfig;
import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.core.util.Utils;
import org.wso2.carbon.utils.ConfigurationContextService;
import org.wso2.carbon.utils.NetworkUtils;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import java.util.*; import java.util.*;
@ -143,24 +141,8 @@ public class APIPublisherUtil {
} }
public static String getServerBaseUrl() { public static String getServerBaseUrl() {
// Hostname WebappPublisherConfig webappPublisherConfig = WebappPublisherConfig.getInstance();
String hostName = "localhost"; return Utils.replaceSystemProperty(webappPublisherConfig.getHost());
try {
hostName = NetworkUtils.getMgtHostName();
} catch (Exception ignored) {
}
// HTTPS port
String mgtConsoleTransport = CarbonUtils.getManagementTransport();
ConfigurationContextService configContextService =
APIPublisherDataHolder.getInstance().getConfigurationContextService();
int port = CarbonUtils.getTransportPort(configContextService, mgtConsoleTransport);
int httpsProxyPort =
CarbonUtils.getTransportProxyPort(configContextService.getServerConfigContext(),
mgtConsoleTransport);
if (httpsProxyPort > 0) {
port = httpsProxyPort;
}
return "https://" + hostName + ":" + port;
} }
public static String getApiEndpointUrl(String context) { public static String getApiEndpointUrl(String context) {

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.apimgt.webapp.publisher;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
/**
* This class contains the util methods which are needed
* to web app publisher related functions.
*/
public class WebappPublisherUtil {
public static Document convertToDocument(File file) throws WebappPublisherConfigurationFailedException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
return docBuilder.parse(file);
} catch (Exception e) {
throw new WebappPublisherConfigurationFailedException("Error occurred while parsing file, while converting " +
"to a org.w3c.dom.Document", e);
}
}
}

@ -26,6 +26,7 @@ import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService;
import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherService; import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherService;
import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherServiceImpl; import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherServiceImpl;
import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherStartupHandler; import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherStartupHandler;
import org.wso2.carbon.apimgt.webapp.publisher.config.WebappPublisherConfig;
import org.wso2.carbon.core.ServerStartupObserver; import org.wso2.carbon.core.ServerStartupObserver;
import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
@ -59,16 +60,23 @@ public class APIPublisherServiceComponent {
protected void activate(ComponentContext componentContext) { protected void activate(ComponentContext componentContext) {
try { try {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Initializing device management core bundle"); log.debug("Initializing webapp publisher bundle");
} }
if (log.isDebugEnabled()) {
log.debug("Loading webapp publisher configurations");
}
/* Initializing webapp publisher configuration */
WebappPublisherConfig.init();
/* Registering declarative service instances exposed by DeviceManagementServiceComponent */ /* Registering declarative service instances exposed by DeviceManagementServiceComponent */
this.registerServices(componentContext); this.registerServices(componentContext);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Device management core bundle has been successfully initialized"); log.debug("Webapp publisher bundle has been successfully initialized");
} }
} catch (Throwable e) { } catch (Throwable e) {
log.error("Error occurred while initializing device management core bundle", e); log.error("Error occurred while initializing webapp publisher bundle", e);
} }
} }

@ -65,7 +65,7 @@ public class EmailSenderServiceComponent {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Initializing email sender core bundle"); log.debug("Initializing email sender core bundle");
} }
/* Initializing email sende configuration */ /* Initializing email sender configuration */
EmailSenderConfig.init(); EmailSenderConfig.init();
/* Setting up default email templates */ /* Setting up default email templates */

@ -113,7 +113,12 @@
org.wso2.carbon.user.core, org.wso2.carbon.user.core,
org.wso2.carbon.user.core.config, org.wso2.carbon.user.core.config,
org.wso2.carbon.user.core.util, org.wso2.carbon.user.core.util,
org.wso2.carbon.utils org.wso2.carbon.utils,
org.wso2.carbon.context,
org.wso2.carbon.identity.oauth.cache,
org.wso2.carbon.identity.oauth.config,
org.wso2.carbon.identity.oauth2.dao,
org.wso2.carbon.utils.multitenancy
</Import-Package> </Import-Package>
</instructions> </instructions>
</configuration> </configuration>

@ -47,6 +47,7 @@ public class OAuthExtUtils {
private static final String DEFAULT_SCOPE_NAME = "default"; private static final String DEFAULT_SCOPE_NAME = "default";
private static final String UI_EXECUTE = "ui.execute"; private static final String UI_EXECUTE = "ui.execute";
private static final String REST_API_SCOPE_CACHE = "REST_API_SCOPE_CACHE"; private static final String REST_API_SCOPE_CACHE = "REST_API_SCOPE_CACHE";
private static final int START_INDEX = 0;
/** /**
* This method is used to get the tenant id when given tenant domain. * This method is used to get the tenant id when given tenant domain.
@ -260,4 +261,12 @@ public class OAuthExtUtils {
return authorizedScopes; return authorizedScopes;
} }
public static String extractUserName(String username) {
if (username == null || username.isEmpty()) {
return null;
}
String trimmedName = username.trim();
return trimmedName.substring(START_INDEX, trimmedName.lastIndexOf('@'));
}
} }

@ -0,0 +1,200 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.oauth.extensions.validators;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
import org.wso2.carbon.identity.application.common.model.User;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.cache.CacheEntry;
import org.wso2.carbon.identity.oauth.cache.OAuthCache;
import org.wso2.carbon.identity.oauth.cache.OAuthCacheKey;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.dao.TokenMgtDAO;
import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
import org.wso2.carbon.identity.oauth2.model.ResourceScopeCacheEntry;
import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator;
import org.wso2.carbon.user.api.AuthorizationManager;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@SuppressWarnings("unused")
public class ExtendedJDBCScopeValidator extends OAuth2ScopeValidator{
private static final Log log = LogFactory.getLog(ExtendedJDBCScopeValidator.class);
private static final String UI_EXECUTE = "ui.execute";
@Override
public boolean validateScope(AccessTokenDO accessTokenDO, String resource) throws IdentityOAuth2Exception {
//Get the list of scopes associated with the access token
String[] scopes = accessTokenDO.getScope();
//If no scopes are associated with the token
if (scopes == null || scopes.length == 0) {
return true;
}
String resourceScope = null;
TokenMgtDAO tokenMgtDAO = new TokenMgtDAO();
boolean cacheHit = false;
// Check the cache, if caching is enabled.
if (OAuthServerConfiguration.getInstance().isCacheEnabled()) {
OAuthCache oauthCache = OAuthCache.getInstance();
OAuthCacheKey cacheKey = new OAuthCacheKey(resource);
CacheEntry result = oauthCache.getValueFromCache(cacheKey);
//Cache hit
if (result instanceof ResourceScopeCacheEntry) {
resourceScope = ((ResourceScopeCacheEntry) result).getScope();
cacheHit = true;
}
}
if (!cacheHit) {
resourceScope = tokenMgtDAO.findScopeOfResource(resource);
if (OAuthServerConfiguration.getInstance().isCacheEnabled()) {
OAuthCache oauthCache = OAuthCache.getInstance();
OAuthCacheKey cacheKey = new OAuthCacheKey(resource);
ResourceScopeCacheEntry cacheEntry = new ResourceScopeCacheEntry(resourceScope);
//Store resourceScope in cache even if it is null (to avoid database calls when accessing resources for
//which scopes haven't been defined).
oauthCache.addToCache(cacheKey, cacheEntry);
}
}
//Return TRUE if - There does not exist a scope definition for the resource
if (resourceScope == null) {
if(log.isDebugEnabled()){
log.debug("Resource '" + resource + "' is not protected with a scope");
}
return true;
}
List<String> scopeList = new ArrayList<>(Arrays.asList(scopes));
//If the access token does not bear the scope required for accessing the Resource.
if(!scopeList.contains(resourceScope)){
if(log.isDebugEnabled()){
log.debug("Access token '" + accessTokenDO.getAccessToken() + "' does not bear the scope '" +
resourceScope + "'");
}
return false;
}
try {
//Get the permissions associated with the scope, if any
Set<String> permissionsOfScope = tokenMgtDAO.getRolesOfScopeByScopeKey(resourceScope);
//If the scope doesn't have any permissions associated with it.
if(permissionsOfScope == null || permissionsOfScope.isEmpty()){
if(log.isDebugEnabled()){
log.debug("Did not find any roles associated to the scope " + resourceScope);
}
return true;
}
if(log.isDebugEnabled()){
StringBuilder logMessage = new StringBuilder("Found permissions of scope '" + resourceScope + "' ");
for(String permission : permissionsOfScope){
logMessage.append(permission);
logMessage.append(", ");
}
log.debug(logMessage.toString());
}
User authorizedUser = accessTokenDO.getAuthzUser();
RealmService realmService = OAuthExtensionsDataHolder.getInstance().getRealmService();
int tenantId = realmService.getTenantManager().getTenantId(authorizedUser.getTenantDomain());
if (tenantId == 0 || tenantId == -1) {
tenantId = IdentityTenantUtil.getTenantIdOfUser(authorizedUser.getUserName());
}
AuthorizationManager authorizationManager;
String[] userRoles;
boolean tenantFlowStarted = false;
try{
//If this is a tenant user
if(tenantId != MultitenantConstants.SUPER_TENANT_ID){
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(
realmService.getTenantManager().getDomain(tenantId),true);
tenantFlowStarted = true;
}
authorizationManager = realmService.getTenantUserRealm(tenantId).getAuthorizationManager();
} finally {
if (tenantFlowStarted) {
PrivilegedCarbonContext.endTenantFlow();
}
}
boolean status = false;
String username = MultitenantUtils.getTenantAwareUsername(authorizedUser.getUserName());
for (String permission : permissionsOfScope) {
if (authorizationManager != null) {
String userStore = authorizedUser.getUserStoreDomain();
if (userStore != null) {
status = authorizationManager
.isUserAuthorized(userStore + "/" + username, permission, UI_EXECUTE);
} else {
status = authorizationManager.isUserAuthorized(username , permission, UI_EXECUTE);
}
if (status) {
break;
}
}
}
if (status) {
if(log.isDebugEnabled()){
log.debug("User '" + authorizedUser.getUserName() + "' is authorized");
}
return true;
}
if(log.isDebugEnabled()){
log.debug("No permissions associated for the user " + authorizedUser.getUserName());
}
return false;
} catch (UserStoreException e) {
//Log and return since we do not want to stop issuing the token in case of scope validation failures.
log.error("Error when getting the tenant's UserStoreManager or when getting roles of user ", e);
return false;
}
}
}

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
~ 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.
-->
<!--
This configuration file represents the configuration that are needed
when publishing APIs to API Manager
-->
<WebappPublisherConfigs>
<!-- This host is used to define the host address which is used to publish APIs -->
<Host>https://${carbon.local.ip}:$(carbon.http.port)</Host>
<!-- If it is true, the APIs of this instance will be published to the defined host -->
<PublishAPI>true</PublishAPI>
</WebappPublisherConfigs>

@ -0,0 +1,2 @@
instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.apimgt.webapp.publisher_${feature.version}/conf/webapp-publisher-config.xml,target:${installFolder}/../../conf/etc/webapp-publisher-config.xml,overwrite:true);\
Loading…
Cancel
Save