revert-70aa11f8
dilanua 9 years ago
commit 330e1a1e19

@ -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.annotations.api;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This class is the representation of custom developed Permission annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
/**
* Represents the scope name.
* @return Returns scope name.
*/
String scope();
/**
* Represents the associated permissions.
* @return Returns list of permissions.
*/
String[] permissions();
}

@ -18,16 +18,17 @@
*/
package org.wso2.carbon.apimgt.webapp.publisher;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.APIProvider;
import org.wso2.carbon.apimgt.api.FaultGatewaysException;
import org.wso2.carbon.apimgt.api.model.API;
import org.wso2.carbon.apimgt.api.model.APIIdentifier;
import org.wso2.carbon.apimgt.api.model.APIStatus;
import org.wso2.carbon.apimgt.api.model.URITemplate;
import org.wso2.carbon.apimgt.api.model.*;
import org.wso2.carbon.apimgt.impl.APIManagerFactory;
import org.wso2.carbon.apimgt.webapp.publisher.internal.APIPublisherDataHolder;
import org.wso2.carbon.context.PrivilegedCarbonContext;
@ -38,10 +39,7 @@ import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.xml.stream.XMLStreamException;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* This class represents the concrete implementation of the APIPublisherService that corresponds to providing all
@ -50,96 +48,123 @@ import java.util.Map;
public class APIPublisherServiceImpl implements APIPublisherService {
private static final Log log = LogFactory.getLog(APIPublisherServiceImpl.class);
private static final String PUBLISH_ACTION = "Publish";
@Override
public void publishAPI(final API api) throws APIManagementException, FaultGatewaysException {
String tenantDomain = MultitenantUtils.getTenantDomain(api.getApiOwner());
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
try {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
// Below code snippet is added to load API Lifecycle in tenant mode.
RegistryService registryService = APIPublisherDataHolder.getInstance().getRegistryService();
CommonUtil.addDefaultLifecyclesIfNotAvailable(registryService.getConfigSystemRegistry(tenantId),
CommonUtil.getRootSystemRegistry(tenantId));
APIProvider provider = APIManagerFactory.getInstance().getAPIProvider(api.getApiOwner());
MultitenantUtils.getTenantDomain(api.getApiOwner());
if (provider != null) {
if (provider.isDuplicateContextTemplate(api.getContext())) {
throw new APIManagementException(
"Error occurred while adding the API. A duplicate API" +
" context already exists for " + api.getContext());
}
if (!provider.isAPIAvailable(api.getId())) {
provider.addAPI(api);
provider.changeLifeCycleStatus(api.getId(), PUBLISH_ACTION);
if (log.isDebugEnabled()) {
log.debug("Successfully published API '" + api.getId().getApiName() +
"' with context '" + api.getContext() + "' and version '"
+ api.getId().getVersion() + "'");
}
} else {
api.setStatus(APIStatus.PUBLISHED);
provider.updateAPI(api);
if (log.isDebugEnabled()) {
log.debug("An API already exists with the name '" + api.getId().getApiName() +
"', context '" + api.getContext() + "' and version '"
+ api.getId().getVersion() + "'. Thus, the API config is updated");
}
}
provider.saveSwagger20Definition(api.getId(), createSwaggerDefinition(api));
} else {
throw new APIManagementException("API provider configured for the given API configuration " +
"is null. Thus, the API is not published");
}
} catch (FileNotFoundException e) {
throw new APIManagementException("Failed to retrieve life cycle file ", e);
} catch (RegistryException e) {
throw new APIManagementException("Failed to access the registry ", e);
} catch (XMLStreamException e) {
throw new APIManagementException("Failed parsing the lifecycle xml.", e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
private String createSwaggerDefinition(API api) {
Map<String, JsonObject> httpVerbsMap = new HashMap<>();
for (URITemplate uriTemplate : api.getUriTemplates()) {
JsonObject response = new JsonObject();
response.addProperty("200", "");
JsonObject responses = new JsonObject();
responses.add("responses", response);
JsonObject httpVerbs = httpVerbsMap.get(uriTemplate.getUriTemplate());
if (httpVerbs == null) {
httpVerbs = new JsonObject();
}
httpVerbs.add(uriTemplate.getHTTPVerb().toLowerCase(), responses);
httpVerbsMap.put(uriTemplate.getUriTemplate(), httpVerbs);
}
Iterator it = httpVerbsMap.entrySet().iterator();
JsonObject paths = new JsonObject();
while (it.hasNext()) {
Map.Entry<String, JsonObject> pair = (Map.Entry) it.next();
paths.add(pair.getKey(), pair.getValue());
it.remove();
}
JsonObject info = new JsonObject();
info.addProperty("title", api.getId().getApiName());
info.addProperty("version", api.getId().getVersion());
JsonObject swaggerDefinition = new JsonObject();
swaggerDefinition.add("paths", paths);
swaggerDefinition.addProperty("swagger", "2.0");
swaggerDefinition.add("info", info);
return swaggerDefinition.toString();
}
private static final String PUBLISH_ACTION = "Publish";
@Override
public void publishAPI(final API api) throws APIManagementException, FaultGatewaysException {
String tenantDomain = MultitenantUtils.getTenantDomain(api.getApiOwner());
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
try {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
// Below code snippet is added to load API Lifecycle in tenant mode.
RegistryService registryService = APIPublisherDataHolder.getInstance().getRegistryService();
CommonUtil.addDefaultLifecyclesIfNotAvailable(registryService.getConfigSystemRegistry(tenantId),
CommonUtil.getRootSystemRegistry(tenantId));
APIProvider provider = APIManagerFactory.getInstance().getAPIProvider(api.getApiOwner());
MultitenantUtils.getTenantDomain(api.getApiOwner());
if (provider != null) {
if (provider.isDuplicateContextTemplate(api.getContext())) {
throw new APIManagementException(
"Error occurred while adding the API. A duplicate API" +
" context already exists for " + api.getContext());
}
if (!provider.isAPIAvailable(api.getId())) {
provider.addAPI(api);
provider.changeLifeCycleStatus(api.getId(), PUBLISH_ACTION);
if (log.isDebugEnabled()) {
log.debug("Successfully published API '" + api.getId().getApiName() +
"' with context '" + api.getContext() + "' and version '"
+ api.getId().getVersion() + "'");
}
} else {
api.setStatus(provider.getAPI(api.getId()).getStatus());
provider.updateAPI(api);
if (log.isDebugEnabled()) {
log.debug("An API already exists with the name '" + api.getId().getApiName() +
"', context '" + api.getContext() + "' and version '"
+ api.getId().getVersion() + "'. Thus, the API config is updated");
}
}
provider.saveSwagger20Definition(api.getId(), createSwaggerDefinition(api));
} else {
throw new APIManagementException("API provider configured for the given API configuration " +
"is null. Thus, the API is not published");
}
} catch (FileNotFoundException e) {
throw new APIManagementException("Failed to retrieve life cycle file ", e);
} catch (RegistryException e) {
throw new APIManagementException("Failed to access the registry ", e);
} catch (XMLStreamException e) {
throw new APIManagementException("Failed parsing the lifecycle xml.", e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
private String createSwaggerDefinition(API api) {
Map<String, JsonObject> httpVerbsMap = new HashMap<>();
List<Scope> scopes = new ArrayList<>();
for (URITemplate uriTemplate : api.getUriTemplates()) {
JsonObject response = new JsonObject();
response.addProperty("200", "");
JsonObject responses = new JsonObject();
responses.add("responses", response);
JsonObject httpVerbs = httpVerbsMap.get(uriTemplate.getUriTemplate());
if (httpVerbs == null) {
httpVerbs = new JsonObject();
}
JsonObject httpVerb = new JsonObject();
httpVerb.add("responses", response);
httpVerb.addProperty("x-auth-type", "Application%20%26%20Application%20User");
httpVerb.addProperty("x-throttling-tier", "Unlimited");
if (uriTemplate.getScope() != null) {
httpVerb.addProperty("x-scope", uriTemplate.getScope().getName());
scopes.add(uriTemplate.getScope());
}
httpVerbs.add(uriTemplate.getHTTPVerb().toLowerCase(), httpVerb);
httpVerbsMap.put(uriTemplate.getUriTemplate(), httpVerbs);
}
Iterator it = httpVerbsMap.entrySet().iterator();
JsonObject paths = new JsonObject();
while (it.hasNext()) {
Map.Entry<String, JsonObject> pair = (Map.Entry) it.next();
paths.add(pair.getKey(), pair.getValue());
it.remove();
}
JsonObject info = new JsonObject();
info.addProperty("title", api.getId().getApiName());
info.addProperty("version", api.getId().getVersion());
JsonObject swaggerDefinition = new JsonObject();
swaggerDefinition.add("paths", paths);
swaggerDefinition.addProperty("swagger", "2.0");
swaggerDefinition.add("info", info);
// adding scopes to swagger definition
if (!api.getScopes().isEmpty()) {
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(api.getScopes(), new TypeToken<Set<Scope>>() {
}.getType());
if (element != null) {
JsonArray apiScopes = element.getAsJsonArray();
JsonObject apim = new JsonObject();
apim.add("x-wso2-scopes", apiScopes);
JsonObject wso2Security = new JsonObject();
wso2Security.add("apim", apim);
swaggerDefinition.add("x-wso2-security", wso2Security);
}
}
if (log.isDebugEnabled()) {
log.debug("API swagger definition: " + swaggerDefinition.toString());
}
return swaggerDefinition.toString();
}
@Override
public void removeAPI(APIIdentifier id) throws APIManagementException {
@ -169,4 +194,5 @@ public class APIPublisherServiceImpl implements APIPublisherService {
log.debug("End of publishing the batch of APIs");
}
}
}

@ -38,38 +38,17 @@ import java.util.*;
public class APIPublisherUtil {
private static final Log log = LogFactory.getLog(APIPublisherUtil.class);
private static final String DEFAULT_API_VERSION = "1.0.0";
public static final String API_VERSION_PARAM = "{version}";
public static final String API_PUBLISH_ENVIRONEMENT = "Production and Sandbox";
public static final String API_PUBLISH_ENVIRONMENT = "Production and Sandbox";
private static final String API_CONFIG_DEFAULT_VERSION = "1.0.0";
private static final String PARAM_MANAGED_API_NAME = "managed-api-name";
private static final String PARAM_MANAGED_API_VERSION = "managed-api-version";
private static final String PARAM_MANAGED_API_CONTEXT = "managed-api-context";
private static final String PARAM_MANAGED_API_ENDPOINT = "managed-api-endpoint";
private static final String PARAM_MANAGED_API_OWNER = "managed-api-owner";
private static final String PARAM_MANAGED_API_TRANSPORTS = "managed-api-transports";
private static final String PARAM_MANAGED_API_IS_SECURED = "managed-api-isSecured";
private static final String PARAM_MANAGED_API_APPLICATION = "managed-api-application";
private static final String PARAM_SHARED_WITH_ALL_TENANTS = "isSharedWithAllTenants";
private static final String PARAM_PROVIDER_TENANT_DOMAIN = "providerTenantDomain";
enum HTTPMethod {
GET, POST, DELETE, PUT, OPTIONS
}
private static List<HTTPMethod> httpMethods;
static {
httpMethods = new ArrayList<HTTPMethod>(5);
httpMethods.add(HTTPMethod.GET);
httpMethods.add(HTTPMethod.POST);
httpMethods.add(HTTPMethod.DELETE);
httpMethods.add(HTTPMethod.PUT);
httpMethods.add(HTTPMethod.OPTIONS);
}
public static API getAPI(APIConfig config) throws APIManagementException {
@ -100,13 +79,11 @@ public class APIPublisherUtil {
api.setStatus(APIStatus.CREATED);
api.setTransports(config.getTransports());
api.setContextTemplate(config.getContextTemplate());
api.setUriTemplates(config.getUriTemplates());
Set<String> environments = new HashSet<>();
environments.add(API_PUBLISH_ENVIRONEMENT);
environments.add(API_PUBLISH_ENVIRONMENT);
api.setEnvironments(environments);
Set<Tier> tiers = new HashSet<>();
Set<Tier> tiers = new HashSet<Tier>();
tiers.add(new Tier(APIConstants.UNLIMITED_TIER));
api.addAvailableTiers(tiers);
@ -132,35 +109,37 @@ public class APIPublisherUtil {
Set<String> tags = new HashSet<>(Arrays.asList(config.getTags()));
api.addTags(tags);
}
return api;
}
private static Set<URITemplate> getURITemplates(String endpoint, String authType) {
Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
if (APIConstants.AUTH_NO_AUTHENTICATION.equals(authType)) {
for (HTTPMethod method : httpMethods) {
URITemplate template = new URITemplate();
template.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
template.setHTTPVerb(method.toString());
template.setResourceURI(endpoint);
template.setUriTemplate("/*");
uriTemplates.add(template);
// adding scopes to the api
Set<URITemplate> uriTemplates = config.getUriTemplates();
Map<String, Scope> apiScopes = new HashMap<>();
if (uriTemplates != null) {
// this creates distinct scopes list
for (URITemplate template : uriTemplates) {
Scope scope = template.getScope();
if (scope != null) {
if (apiScopes.get(scope.getKey()) == null) {
apiScopes.put(scope.getKey(), scope);
}
}
}
} else {
for (HTTPMethod method : httpMethods) {
URITemplate template = new URITemplate();
if (HTTPMethod.OPTIONS.equals(method)) {
template.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
} else {
template.setAuthType(APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN);
Set<Scope> scopes = new HashSet<>(apiScopes.values());
api.setScopes(scopes);
// this has to be done because of the use of pass by reference
// where same object reference of scope should be available for both
// api scope and uri template scope
for (Scope scope : scopes) {
for (URITemplate template : uriTemplates) {
if (scope.getKey().equals(template.getScope().getKey())) {
template.setScope(scope);
}
}
template.setHTTPVerb(method.toString());
template.setResourceURI(endpoint);
template.setUriTemplate("/*");
uriTemplates.add(template);
}
api.setUriTemplates(uriTemplates);
}
return uriTemplates;
return api;
}
public static String getServerBaseUrl() {
@ -225,12 +204,13 @@ public class APIPublisherUtil {
* Build the API Configuration to be passed to APIM, from a given list of URL templates
*
* @param servletContext
* @param apiDef
* @return
*/
public static APIConfig buildApiConfig(ServletContext servletContext, APIResourceConfiguration apidef) {
public static APIConfig buildApiConfig(ServletContext servletContext, APIResourceConfiguration apiDef) {
APIConfig apiConfig = new APIConfig();
String name = apidef.getName();
String name = apiDef.getName();
if (name == null || name.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("API Name not set in @API Annotation");
@ -239,7 +219,7 @@ public class APIPublisherUtil {
}
apiConfig.setName(name);
String version = apidef.getVersion();
String version = apiDef.getVersion();
if (version == null || version.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("'API Version not set in @API Annotation'");
@ -249,7 +229,7 @@ public class APIPublisherUtil {
apiConfig.setVersion(version);
String context = apidef.getContext();
String context = apiDef.getContext();
if (context == null || context.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("'API Context not set in @API Annotation'");
@ -258,7 +238,7 @@ public class APIPublisherUtil {
}
apiConfig.setContext(context);
String[] tags = apidef.getTags();
String[] tags = apiDef.getTags();
if (tags == null || tags.length == 0) {
if (log.isDebugEnabled()) {
log.debug("'API tag not set in @API Annotation'");
@ -323,13 +303,14 @@ public class APIPublisherUtil {
&& Boolean.parseBoolean(sharingValueParam));
apiConfig.setSharedWithAllTenants(isSharedWithAllTenants);
Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
for (APIResource apiResource : apidef.getResources()) {
Set<URITemplate> uriTemplates = new LinkedHashSet<>();
for (APIResource apiResource : apiDef.getResources()) {
URITemplate template = new URITemplate();
template.setAuthType(apiResource.getAuthType());
template.setHTTPVerb(apiResource.getHttpVerb());
template.setResourceURI(apiResource.getUri());
template.setUriTemplate(apiResource.getUriTemplate());
template.setScope(apiResource.getScope());
uriTemplates.add(template);
}
apiConfig.setUriTemplates(uriTemplates);

@ -18,70 +18,71 @@
package org.wso2.carbon.apimgt.webapp.publisher.config;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Resource")
public class APIResource{
private String AuthType;
private String HttpVerb;
private String Uri;
private String UriTemplate;
private String consumes;
private String produces;
public String getAuthType() {
return AuthType;
}
@XmlElement(name = "AuthType", required = true)
public void setAuthType(String authType) {
AuthType = authType;
}
public String getHttpVerb() {
return HttpVerb;
}
@XmlElement(name = "HttpVerb", required = true)
public void setHttpVerb(String httpVerb) {
HttpVerb = httpVerb;
}
public String getUri() {
return Uri;
}
@XmlElement(name = "Uri", required = true)
public void setUri(String uri) {
Uri = uri;
}
public String getUriTemplate() {
return UriTemplate;
}
@XmlElement(name = "UriTemplate", required = true)
public void setUriTemplate(String uriTemplate) {
UriTemplate = uriTemplate;
}
public String getConsumes() {
return consumes;
}
@XmlElement(name = "Consumes", required = true)
public void setConsumes(String consumes) {
this.consumes = consumes;
}
public String getProduces() {
return produces;
}
@XmlElement(name = "Produces", required = true)
public void setProduces(String produces) {
this.produces = produces;
}
import org.wso2.carbon.apimgt.api.model.Scope;
public class APIResource {
private String AuthType;
private String HttpVerb;
private String Uri;
private String UriTemplate;
private String consumes;
private String produces;
private Scope scope;
public String getAuthType() {
return AuthType;
}
public void setAuthType(String authType) {
AuthType = authType;
}
public String getHttpVerb() {
return HttpVerb;
}
public void setHttpVerb(String httpVerb) {
HttpVerb = httpVerb;
}
public String getUri() {
return Uri;
}
public void setUri(String uri) {
Uri = uri;
}
public String getUriTemplate() {
return UriTemplate;
}
public void setUriTemplate(String uriTemplate) {
UriTemplate = uriTemplate;
}
public String getConsumes() {
return consumes;
}
public void setConsumes(String consumes) {
this.consumes = consumes;
}
public String getProduces() {
return produces;
}
public void setProduces(String produces) {
this.produces = produces;
}
public Scope getScope() {
return scope;
}
public void setScope(Scope scope) {
this.scope = scope;
}
}

@ -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.config;
/**
* This class represents the information related to permissions.
*/
public class PermissionConfiguration {
private String scopeName;
private String[] permissions;
public String getScopeName() {
return scopeName;
}
public void setScopeName(String scope) {
this.scopeName = scope;
}
public String[] getPermissions() {
return permissions;
}
public void setPermissions(String[] permissions) {
this.permissions = permissions;
}
}

@ -0,0 +1,60 @@
/*
* 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.
*/
package org.wso2.carbon.apimgt.webapp.publisher.config;
/**
* Custom exception class of Permission related operations.
*/
public class PermissionManagementException extends Exception {
private static final long serialVersionUID = -3151279311929070298L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public PermissionManagementException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public PermissionManagementException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public PermissionManagementException(String msg) {
super(msg);
setErrorMessage(msg);
}
public PermissionManagementException() {
super();
}
public PermissionManagementException(Throwable cause) {
super(cause);
}
}

@ -24,8 +24,10 @@ import org.apache.catalina.LifecycleListener;
import org.apache.catalina.core.StandardContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.api.model.*;
import org.wso2.carbon.apimgt.webapp.publisher.*;
import org.wso2.carbon.apimgt.api.model.API;
import org.wso2.carbon.apimgt.webapp.publisher.APIConfig;
import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherService;
import org.wso2.carbon.apimgt.webapp.publisher.APIPublisherUtil;
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.lifecycle.util.AnnotationUtil;
@ -39,7 +41,6 @@ import java.util.Set;
public class APIPublisherLifecycleListener implements LifecycleListener {
private static final Log log = LogFactory.getLog(APIPublisherLifecycleListener.class);
private static final String PARAM_MANAGED_API_ENABLED = "managed-api-enabled";
@Override
@ -55,6 +56,7 @@ public class APIPublisherLifecycleListener implements LifecycleListener {
AnnotationUtil annotationUtil = new AnnotationUtil(context);
Set<String> annotatedAPIClasses = annotationUtil.
scanStandardContext(org.wso2.carbon.apimgt.annotations.api.API.class.getName());
List<APIResourceConfiguration> apiDefinitions = annotationUtil.extractAPIInfo(servletContext,
annotatedAPIClasses);

@ -20,13 +20,18 @@ package org.wso2.carbon.apimgt.webapp.publisher.lifecycle.util;
import org.apache.catalina.core.StandardContext;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scannotation.AnnotationDB;
import org.scannotation.WarUrlFinder;
import org.wso2.carbon.apimgt.annotations.api.API;
import org.wso2.carbon.apimgt.annotations.api.Permission;
import org.wso2.carbon.apimgt.api.model.Scope;
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.PermissionConfiguration;
import org.wso2.carbon.apimgt.webapp.publisher.config.PermissionManagementException;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
@ -38,7 +43,9 @@ import java.lang.reflect.Proxy;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class AnnotationUtil {
@ -118,7 +125,6 @@ public class AnnotationUtil {
.class.getName());
Annotation apiAnno = clazz.getAnnotation(apiClazz);
List<APIResource> resourceList;
if (apiAnno != null) {
@ -224,7 +230,6 @@ public class AnnotationUtil {
Annotation[] annotations = method.getDeclaredAnnotations();
for (int i = 0; i < annotations.length; i++) {
processHTTPMethodAnnotation(resource, annotations[i]);
if (annotations[i].annotationType().getName().equals(Consumes.class.getName())) {
Class<Consumes> consumesClass = (Class<Consumes>) classLoader.loadClass(
@ -240,6 +245,18 @@ public class AnnotationUtil {
Annotation producesAnno = method.getAnnotation(producesClass);
resource.setProduces(invokeMethod(producesClassMethods[0], producesAnno, STRING_ARR));
}
if (annotations[i].annotationType().getName().equals(Permission.class.getName())) {
PermissionConfiguration permissionConf = this.getPermission(method);
if (permissionConf != null) {
Scope scope = new Scope();
scope.setKey(permissionConf.getScopeName());
scope.setDescription(permissionConf.getScopeName());
scope.setName(permissionConf.getScopeName());
String roles = StringUtils.join(permissionConf.getPermissions(), ",");
scope.setRoles(roles);
resource.setScope(scope);
}
}
}
resourceList.add(resource);
}
@ -314,4 +331,34 @@ public class AnnotationUtil {
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
return ((String[]) methodHandler.invoke(annotation, method, null));
}
private PermissionConfiguration getPermission(Method currentMethod) throws Throwable {
Class<Permission> permissionClass = (Class<Permission>) classLoader.loadClass(Permission.class.getName());
Annotation permissionAnnotation = currentMethod.getAnnotation(permissionClass);
if (permissionClass != null) {
Method[] permissionClassMethods = permissionClass.getMethods();
PermissionConfiguration permissionConf = new PermissionConfiguration();
for (Method method : permissionClassMethods) {
switch (method.getName()) {
case "scope":
permissionConf.setScopeName(invokeMethod(method, permissionAnnotation, STRING));
break;
case "permissions":
String permissions[] = invokeMethod(method, permissionAnnotation);
this.addPermission(permissions);
permissionConf.setPermissions(permissions);
break;
}
}
return permissionConf;
}
return null;
}
private void addPermission(String[] permissions) throws PermissionManagementException {
for (String permission : permissions) {
PermissionUtils.addPermission(permission);
}
}
}

@ -0,0 +1,91 @@
/*
* 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.
*/
package org.wso2.carbon.apimgt.webapp.publisher.lifecycle.util;
import org.wso2.carbon.apimgt.webapp.publisher.config.PermissionManagementException;
import org.wso2.carbon.apimgt.webapp.publisher.internal.APIPublisherDataHolder;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.registry.api.RegistryException;
import org.wso2.carbon.registry.api.Resource;
import org.wso2.carbon.registry.core.Registry;
import java.util.StringTokenizer;
/**
* Utility class which holds necessary utility methods required for persisting permissions in
* registry.
*/
public class PermissionUtils {
public static final String ADMIN_PERMISSION_REGISTRY_PATH = "/permission/admin";
public static final String PERMISSION_PROPERTY_NAME = "name";
public static Registry getGovernanceRegistry() throws PermissionManagementException {
try {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
return APIPublisherDataHolder.getInstance().getRegistryService()
.getGovernanceSystemRegistry(
tenantId);
} catch (RegistryException e) {
throw new PermissionManagementException(
"Error in retrieving governance registry instance: " +
e.getMessage(), e);
}
}
public static void addPermission(String permission) throws PermissionManagementException {
String resourcePermission = getAbsolutePermissionPath(permission);
try {
StringTokenizer tokenizer = new StringTokenizer(resourcePermission, "/");
String lastToken = "", currentToken, tempPath;
while (tokenizer.hasMoreTokens()) {
currentToken = tokenizer.nextToken();
tempPath = lastToken + "/" + currentToken;
if (!checkResourceExists(tempPath)) {
createRegistryCollection(tempPath, currentToken);
}
lastToken = tempPath;
}
} catch (RegistryException e) {
throw new PermissionManagementException("Error occurred while persisting permission : " +
resourcePermission, e);
}
}
public static void createRegistryCollection(String path, String resourceName)
throws PermissionManagementException,
RegistryException {
Resource resource = PermissionUtils.getGovernanceRegistry().newCollection();
resource.addProperty(PERMISSION_PROPERTY_NAME, resourceName);
PermissionUtils.getGovernanceRegistry().beginTransaction();
PermissionUtils.getGovernanceRegistry().put(path, resource);
PermissionUtils.getGovernanceRegistry().commitTransaction();
}
public static boolean checkResourceExists(String path)
throws PermissionManagementException,
org.wso2.carbon.registry.core.exceptions.RegistryException {
return PermissionUtils.getGovernanceRegistry().resourceExists(path);
}
private static String getAbsolutePermissionPath(String permissionPath) {
return PermissionUtils.ADMIN_PERMISSION_REGISTRY_PATH + permissionPath;
}
}

@ -45,23 +45,23 @@ import java.util.List;
@SuppressWarnings("unused")
public class WebAppDeploymentLifecycleListener implements LifecycleListener {
private static final String PERMISSION_CONFIG_PATH = "META-INF" + File.separator + "permissions.xml";
private static final Log log = LogFactory.getLog(WebAppDeploymentLifecycleListener.class);
private static final String PERMISSION_CONFIG_PATH = "META-INF" + File.separator + "permissions.xml";
private static final Log log = LogFactory.getLog(WebAppDeploymentLifecycleListener.class);
@Override
public void lifecycleEvent(LifecycleEvent lifecycleEvent) {
if (Lifecycle.AFTER_START_EVENT.equals(lifecycleEvent.getType())) {
StandardContext context = (StandardContext) lifecycleEvent.getLifecycle();
ServletContext servletContext = context.getServletContext();
String contextPath = context.getServletContext().getContextPath();
try {
InputStream permissionStream = servletContext.getResourceAsStream(PERMISSION_CONFIG_PATH);
if (permissionStream != null) {
@Override
public void lifecycleEvent(LifecycleEvent lifecycleEvent) {
if (Lifecycle.AFTER_START_EVENT.equals(lifecycleEvent.getType())) {
StandardContext context = (StandardContext) lifecycleEvent.getLifecycle();
ServletContext servletContext = context.getServletContext();
String contextPath = context.getServletContext().getContextPath();
try {
InputStream permissionStream = servletContext.getResourceAsStream(PERMISSION_CONFIG_PATH);
if (permissionStream != null) {
/* Un-marshaling Device Management configuration */
JAXBContext cdmContext = JAXBContext.newInstance(PermissionConfiguration.class);
Unmarshaller unmarshaller = cdmContext.createUnmarshaller();
PermissionConfiguration permissionConfiguration = (PermissionConfiguration)
unmarshaller.unmarshal(permissionStream);
JAXBContext cdmContext = JAXBContext.newInstance(PermissionConfiguration.class);
Unmarshaller unmarshaller = cdmContext.createUnmarshaller();
PermissionConfiguration permissionConfiguration = (PermissionConfiguration)
unmarshaller.unmarshal(permissionStream);
List<Permission> permissions = permissionConfiguration.getPermissions();
String apiVersion = permissionConfiguration.getApiVersion();
if (permissionConfiguration != null && permissions != null) {
@ -69,22 +69,22 @@ public class WebAppDeploymentLifecycleListener implements LifecycleListener {
// update the permission path to absolute permission path
permission.setPath(PermissionUtils.getAbsolutePermissionPath(permission.getPath()));
permission.setUrl(PermissionUtils.getAbsoluteContextPathOfAPI(contextPath, apiVersion,
permission.getUrl()).toLowerCase());
permission.getUrl()).toLowerCase());
permission.setMethod(permission.getMethod().toUpperCase());
PermissionManagerServiceImpl.getInstance().addPermission(permission);
}
}
}
} catch (JAXBException e) {
}
}
} catch (JAXBException e) {
log.error(
"Exception occurred while parsing the permission configuration of webapp : "
+ context.getServletContext().getContextPath(), e);
+ context.getServletContext().getContextPath(), e);
} catch (PermissionManagementException e) {
log.error("Exception occurred while adding the permissions from webapp : "
+ servletContext.getContextPath(), e);
+ servletContext.getContextPath(), e);
}
}
}
}
}

@ -17,7 +17,8 @@
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
@ -47,8 +48,12 @@
<artifactId>org.wso2.carbon.user.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.user.api</artifactId>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.impl</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId>
</dependency>
</dependencies>
@ -89,8 +94,25 @@
org.wso2.carbon.user.api,
org.wso2.carbon.user.core.service,
org.wso2.carbon.identity.application.common.model,
org.wso2.carbon.identity.application.authentication.framework.model,
org.wso2.carbon.user.core.tenant
org.wso2.carbon.identity.application.authentication.framework.model,
org.wso2.carbon.user.core.tenant,
org.json.simple,
javax.cache,
javax.xml.namespace,
org.apache.axiom.om,
org.wso2.carbon.apimgt.api,
org.wso2.carbon.apimgt.impl,
org.wso2.carbon.apimgt.impl.dao,
org.wso2.carbon.apimgt.impl.utils,
org.wso2.carbon.identity.application.common.cache,
org.wso2.carbon.identity.core.util,
org.wso2.carbon.identity.oauth2.dto,
org.wso2.carbon.identity.oauth2.token,
org.wso2.carbon.identity.oauth2.token.handlers.grant,
org.wso2.carbon.user.core,
org.wso2.carbon.user.core.config,
org.wso2.carbon.user.core.util,
org.wso2.carbon.utils
</Import-Package>
</instructions>
</configuration>

@ -20,9 +20,23 @@ package org.wso2.carbon.device.mgt.oauth.extensions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO;
import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import javax.cache.Caching;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* This class holds util methods used by OAuth extension bundle.
@ -30,7 +44,16 @@ import org.wso2.carbon.user.api.UserStoreException;
public class OAuthExtUtils {
private static final Log log = LogFactory.getLog(OAuthExtUtils.class);
private static final String DEFAULT_SCOPE_NAME = "default";
private static final String UI_EXECUTE = "ui.execute";
private static final String REST_API_SCOPE_CACHE = "REST_API_SCOPE_CACHE";
/**
* This method is used to get the tenant id when given tenant domain.
*
* @param tenantDomain Tenant domain name.
* @return Returns the tenant id.
*/
public static int getTenantId(String tenantDomain) {
int tenantId = 0;
if (tenantDomain != null) {
@ -39,10 +62,202 @@ public class OAuthExtUtils {
tenantId = tenantManager.getTenantId(tenantDomain);
} catch (UserStoreException e) {
String errorMsg = "Error when getting the tenant id from the tenant domain : " +
tenantDomain;
tenantDomain;
log.error(errorMsg, e);
}
}
return tenantId;
}
/**
* This method is used to set scopes that are authorized to the OAuth token request message context.
*
* @param tokReqMsgCtx OAuth token request message context
* @return Returns true if success.
*/
public static boolean setScopes(OAuthTokenReqMessageContext tokReqMsgCtx) {
String[] requestedScopes = tokReqMsgCtx.getScope();
String[] defaultScope = new String[]{DEFAULT_SCOPE_NAME};
//If no scopes were requested.
if (requestedScopes == null || requestedScopes.length == 0) {
tokReqMsgCtx.setScope(defaultScope);
return true;
}
String consumerKey = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
List<String> reqScopeList = Arrays.asList(requestedScopes);
Map<String, String> restAPIScopesOfCurrentTenant;
try {
Map<String, String> appScopes;
ApiMgtDAO apiMgtDAO = new ApiMgtDAO();
//Get all the scopes and permissions against the scopes defined for the APIs subscribed to the application.
appScopes = apiMgtDAO.getScopeRolesOfApplication(consumerKey);
//Add API Manager rest API scopes set. This list should be loaded at server start up and keep
//in memory and add it to each and every request coming.
String tenantDomain = tokReqMsgCtx.getAuthorizedUser().getTenantDomain();
restAPIScopesOfCurrentTenant = (Map) Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
.getCache(REST_API_SCOPE_CACHE)
.get(tenantDomain);
if (restAPIScopesOfCurrentTenant != null) {
appScopes.putAll(restAPIScopesOfCurrentTenant);
} else {
restAPIScopesOfCurrentTenant = APIUtil.
getRESTAPIScopesFromConfig(APIUtil.getTenantRESTAPIScopesConfig(tenantDomain));
//call load tenant config for rest API.
//then put cache
appScopes.putAll(restAPIScopesOfCurrentTenant);
Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
.getCache(REST_API_SCOPE_CACHE)
.put(tenantDomain, restAPIScopesOfCurrentTenant);
}
//If no scopes can be found in the context of the application
if (appScopes.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("No scopes defined for the Application " +
tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId());
}
String[] allowedScopes = getAllowedScopes(reqScopeList);
tokReqMsgCtx.setScope(allowedScopes);
return true;
}
// check for authorized scopes
List<String> authorizedScopes = getAuthorizedScopes(tokReqMsgCtx, reqScopeList, appScopes);
if (!authorizedScopes.isEmpty()) {
String[] authScopesArr = authorizedScopes.toArray(new String[authorizedScopes.size()]);
tokReqMsgCtx.setScope(authScopesArr);
} else {
tokReqMsgCtx.setScope(defaultScope);
}
} catch (APIManagementException e) {
log.error("Error while getting scopes of application " + e.getMessage());
return false;
}
return true;
}
/**
* Determines if the scope is specified in the white list.
*
* @param scope - The scope key to check
* @return - 'true' if the scope is white listed. 'false' if not.
*/
private static boolean isWhiteListedScope(String scope) {
// load white listed scopes
List<String> scopeSkipList = OAuthExtensionsDataHolder.getInstance().getWhitelistedScopes();
for (String scopeTobeSkipped : scopeSkipList) {
if (scope.matches(scopeTobeSkipped)) {
return true;
}
}
return false;
}
/**
* Get the set of default scopes. If a requested scope is matches with the patterns specified in the white list,
* then such scopes will be issued without further validation. If the scope list is empty,
* token will be issued for default scope.
*
* @param requestedScopes - The set of requested scopes
* @return - The subset of scopes that are allowed
*/
private static String[] getAllowedScopes(List<String> requestedScopes) {
List<String> authorizedScopes = new ArrayList<>();
//Iterate the requested scopes list.
for (String scope : requestedScopes) {
if (isWhiteListedScope(scope)) {
authorizedScopes.add(scope);
}
}
if (authorizedScopes.isEmpty()) {
authorizedScopes.add(DEFAULT_SCOPE_NAME);
}
return authorizedScopes.toArray(new String[authorizedScopes.size()]);
}
/**
* This method is used to get the authorized scopes out of requested scopes. It checks requested scopes with app
* scopes whether user has permissions to take actions for the requested scopes.
*
* @param tokReqMsgCtx OAuth token request message context.
* @param reqScopeList Requested scope list.
* @param appScopes App scopes.
* @return Returns a list of scopes.
*/
private static List<String> getAuthorizedScopes(OAuthTokenReqMessageContext tokReqMsgCtx, List<String> reqScopeList,
Map<String, String> appScopes) {
boolean status;
List<String> authorizedScopes = new ArrayList<>();
int tenantId;
String username = tokReqMsgCtx.getAuthorizedUser().getUserName();
String tenantDomain = tokReqMsgCtx.getAuthorizedUser().getTenantDomain();
RealmService realmService = OAuthExtensionsDataHolder.getInstance().getRealmService();
try {
tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
// If tenant Id is not set in the tokenReqContext, deriving it from username.
if (tenantId == 0 || tenantId == -1) {
tenantId = IdentityTenantUtil.getTenantIdOfUser(username);
}
UserRealm userRealm = OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
//Iterate the requested scopes list.
for (String scope : reqScopeList) {
status = false;
//Get the set of roles associated with the requested scope.
String appPermissions = appScopes.get(scope);
//If the scope has been defined in the context of the App and if permissions have been defined for the scope
if (appPermissions != null && appPermissions.length() != 0) {
List<String> permissions = new ArrayList<>(Arrays.asList(appPermissions.replaceAll(" ", "").split(",")));
//Check if user has at least one of the permission associated with the scope
if (!permissions.isEmpty()) {
for (String permission : permissions) {
if (userRealm != null && userRealm.getAuthorizationManager() != null) {
String userStore = tokReqMsgCtx.getAuthorizedUser().getUserStoreDomain();
if (userStore != null) {
status = userRealm.getAuthorizationManager()
.isUserAuthorized(userStore + "/" + username, permission, UI_EXECUTE);
} else {
status = userRealm.getAuthorizationManager()
.isUserAuthorized(username, permission, UI_EXECUTE);
}
if (status) {
break;
}
}
}
if (status) {
authorizedScopes.add(scope);
}
}
}
//The scope string starts with 'device_'.
else if (appScopes.containsKey(scope) || isWhiteListedScope(scope)) {
authorizedScopes.add(scope);
}
}
} catch (UserStoreException e) {
log.error("Error occurred while initializing user store.", e);
}
return authorizedScopes;
}
}

@ -0,0 +1,328 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.oauth.extensions.handlers.grant;
import org.apache.axiom.om.OMElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthExtUtils;
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
import org.wso2.carbon.identity.application.common.cache.BaseCache;
import org.wso2.carbon.identity.core.util.IdentityConfigParser;
import org.wso2.carbon.identity.core.util.IdentityCoreConstants;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.ResponseHeader;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.token.handlers.grant.PasswordGrantHandler;
import org.wso2.carbon.user.api.Claim;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.config.RealmConfiguration;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import javax.xml.namespace.QName;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@SuppressWarnings("unused")
public class ExtendedPasswordGrantHandler extends PasswordGrantHandler {
private static Log log = LogFactory.getLog(ExtendedPasswordGrantHandler.class);
private static final String CONFIG_ELEM_OAUTH = "OAuth";
// Claims that are set as response headers of access token response
private static final String REQUIRED_CLAIM_URIS = "RequiredRespHeaderClaimUris";
private BaseCache<String, Claim[]> userClaimsCache;
// Primary/Secondary Login configuration
private static final String CLAIM_URI = "ClaimUri";
private static final String LOGIN_CONFIG = "LoginConfig";
private static final String USERID_LOGIN = "UserIdLogin";
private static final String EMAIL_LOGIN = "EmailLogin";
private static final String PRIMARY_LOGIN = "primary";
private Map<String, Map<String, String>> loginConfiguration = new ConcurrentHashMap<>();
private List<String> requiredHeaderClaimUris = new ArrayList<>();
public void init() throws IdentityOAuth2Exception {
super.init();
IdentityConfigParser configParser;
configParser = IdentityConfigParser.getInstance();
OMElement oauthElem = configParser.getConfigElement(CONFIG_ELEM_OAUTH);
// Get the required claim uris that needs to be included in the response.
parseRequiredHeaderClaimUris(oauthElem.getFirstChildWithName(getQNameWithIdentityNS(REQUIRED_CLAIM_URIS)));
// read login config
parseLoginConfig(oauthElem);
userClaimsCache = new BaseCache<>("UserClaimsCache");
if (log.isDebugEnabled()) {
log.debug("Successfully created UserClaimsCache under " + OAuthConstants.OAUTH_CACHE_MANAGER);
}
}
@Override
public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx)
throws IdentityOAuth2Exception {
OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO = tokReqMsgCtx.getOauth2AccessTokenReqDTO();
String username = oAuth2AccessTokenReqDTO.getResourceOwnerUsername();
String loginUserName = getLoginUserName(username);
tokReqMsgCtx.getOauth2AccessTokenReqDTO().setResourceOwnerUsername(loginUserName);
boolean isValidated = super.validateGrant(tokReqMsgCtx);
if (isValidated) {
int tenantId;
tenantId = IdentityTenantUtil.getTenantIdOfUser(username);
RealmService realmService = OAuthExtensionsDataHolder.getInstance().getRealmService();
UserStoreManager userStoreManager;
try {
userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
} catch (UserStoreException e) {
log.error("Error when getting the tenant's UserStoreManager", e);
return false;
}
List<ResponseHeader> respHeaders = new ArrayList<>();
if (oAuth2AccessTokenReqDTO.getResourceOwnerUsername() != null) {
try {
if (requiredHeaderClaimUris != null && !requiredHeaderClaimUris.isEmpty()) {
// Get user's claim values from the default profile.
String userStoreDomain = tokReqMsgCtx.getAuthorizedUser().getUserStoreDomain();
String endUsernameWithDomain = UserCoreUtil.
addDomainToName(oAuth2AccessTokenReqDTO.getResourceOwnerUsername(), userStoreDomain);
Claim[] mapClaimValues = getUserClaimValues(endUsernameWithDomain, userStoreManager);
if (mapClaimValues != null && mapClaimValues.length > 0) {
ResponseHeader header;
for (String claimUri : requiredHeaderClaimUris) {
for (Claim claim : mapClaimValues) {
if (claimUri.equals(claim.getClaimUri())) {
header = new ResponseHeader();
header.setKey(claim.getDisplayTag());
header.setValue(claim.getValue());
respHeaders.add(header);
break;
}
}
}
} else if (log.isDebugEnabled()) {
log.debug("No claim values for user : " + endUsernameWithDomain);
}
}
} catch (Exception e) {
throw new IdentityOAuth2Exception("Error occurred while retrieving user claims", e);
}
}
tokReqMsgCtx.addProperty("RESPONSE_HEADERS", respHeaders.toArray(new ResponseHeader[respHeaders.size()]));
}
return isValidated;
}
@Override
public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) {
return OAuthExtUtils.setScopes(tokReqMsgCtx);
}
private String getLoginUserName(String userID) {
String loginUserName = userID;
if (isSecondaryLogin(userID)) {
loginUserName = getPrimaryFromSecondary(userID);
}
return loginUserName;
}
/**
* Identify whether the logged in user used his Primary Login name or
* Secondary login name
*
* @param userId - The username used to login.
* @return <code>true</code> if secondary login name is used,
* <code>false</code> if primary login name has been used
*/
private boolean isSecondaryLogin(String userId) {
if (loginConfiguration.get(EMAIL_LOGIN) != null) {
Map<String, String> emailConf = loginConfiguration.get(EMAIL_LOGIN);
if ("true".equalsIgnoreCase(emailConf.get(PRIMARY_LOGIN))) {
return !isUserLoggedInEmail(userId);
} else if ("false".equalsIgnoreCase(emailConf.get(PRIMARY_LOGIN))) {
return isUserLoggedInEmail(userId);
}
} else if (loginConfiguration.get(USERID_LOGIN) != null) {
Map<String, String> userIdConf = loginConfiguration.get(USERID_LOGIN);
if ("true".equalsIgnoreCase(userIdConf.get(PRIMARY_LOGIN))) {
return isUserLoggedInEmail(userId);
} else if ("false".equalsIgnoreCase(userIdConf.get(PRIMARY_LOGIN))) {
return !isUserLoggedInEmail(userId);
}
}
return false;
}
/**
* Identify whether the logged in user used his ordinal username or email
*
* @param userId - username used to login.
* @return - <code>true</code> if userId contains '@'. <code>false</code> otherwise
*/
private boolean isUserLoggedInEmail(String userId) {
return userId.contains("@");
}
/**
* Get the primaryLogin name using secondary login name. Primary secondary
* Configuration is provided in the identitiy.xml. In the userstore, it is
* users responsibility TO MAINTAIN THE SECONDARY LOGIN NAME AS UNIQUE for
* each and every users. If it is not unique, we will pick the very first
* entry from the userlist.
*
* @param login - username used to login.
* @return -
*/
private String getPrimaryFromSecondary(String login) {
String claimURI, username = null;
if (isUserLoggedInEmail(login)) {
Map<String, String> emailConf = loginConfiguration.get(EMAIL_LOGIN);
claimURI = emailConf.get(CLAIM_URI);
} else {
Map<String, String> userIdConf = loginConfiguration.get(USERID_LOGIN);
claimURI = userIdConf.get(CLAIM_URI);
}
try {
RealmService realmSvc = OAuthExtensionsDataHolder.getInstance().getRealmService();
RealmConfiguration config = new RealmConfiguration();
UserRealm realm = realmSvc.getUserRealm(config);
org.wso2.carbon.user.core.UserStoreManager storeManager = realm.getUserStoreManager();
String[] user = storeManager.getUserList(claimURI, login, null);
if (user.length > 0) {
username = user[0];
}
} catch (UserStoreException e) {
log.error("Error while retrieving the primaryLogin name using secondary login name : " + login, e);
}
return username;
}
private Claim[] getUserClaimValues(String authorizedUser, UserStoreManager userStoreManager)
throws
UserStoreException {
Claim[] userClaims = userClaimsCache.getValueFromCache(authorizedUser);
if (userClaims != null) {
return userClaims;
} else {
if (log.isDebugEnabled()) {
log.debug("Cache miss for user claims. Username :" + authorizedUser);
}
userClaims = userStoreManager.getUserClaimValues(
authorizedUser, null);
userClaimsCache.addToCache(authorizedUser, userClaims);
return userClaims;
}
}
/**
* Read the required claim configuration from identity.xml
*/
private void parseRequiredHeaderClaimUris(OMElement requiredClaimUrisElem) {
if (requiredClaimUrisElem == null) {
return;
}
Iterator claimUris = requiredClaimUrisElem.getChildrenWithLocalName(CLAIM_URI);
if (claimUris != null) {
while (claimUris.hasNext()) {
OMElement claimUri = (OMElement) claimUris.next();
if (claimUri != null) {
requiredHeaderClaimUris.add(claimUri.getText());
}
}
}
}
/**
* Read the primary/secondary login configuration
* <OAuth>
* ....
* <LoginConfig>
* <UserIdLogin primary="true">
* <ClaimUri></ClaimUri>
* </UserIdLogin>
* <EmailLogin primary="false">
* <ClaimUri>http://wso2.org/claims/emailaddress</ClaimUri>
* </EmailLogin>
* </LoginConfig>
* .....
* </OAuth>
*
* @param oauthConfigElem - The '<LoginConfig>' xml configuration element in the api-manager.xml
*/
private void parseLoginConfig(OMElement oauthConfigElem) {
OMElement loginConfigElem = oauthConfigElem.getFirstChildWithName(getQNameWithIdentityNS(LOGIN_CONFIG));
if (loginConfigElem != null) {
if (log.isDebugEnabled()) {
log.debug("Login configuration is set ");
}
// Primary/Secondary supported login mechanisms
OMElement emailConfigElem = loginConfigElem.getFirstChildWithName(getQNameWithIdentityNS(EMAIL_LOGIN));
OMElement userIdConfigElem = loginConfigElem.getFirstChildWithName(getQNameWithIdentityNS(USERID_LOGIN));
Map<String, String> emailConf = new HashMap<String, String>(2);
emailConf.put(PRIMARY_LOGIN,
emailConfigElem.getAttributeValue(new QName(PRIMARY_LOGIN)));
emailConf.put(CLAIM_URI,
emailConfigElem.getFirstChildWithName(getQNameWithIdentityNS(CLAIM_URI))
.getText());
Map<String, String> userIdConf = new HashMap<String, String>(2);
userIdConf.put(PRIMARY_LOGIN,
userIdConfigElem.getAttributeValue(new QName(PRIMARY_LOGIN)));
userIdConf.put(CLAIM_URI,
userIdConfigElem.getFirstChildWithName(getQNameWithIdentityNS(CLAIM_URI))
.getText());
loginConfiguration.put(EMAIL_LOGIN, emailConf);
loginConfiguration.put(USERID_LOGIN, userIdConf);
}
}
private QName getQNameWithIdentityNS(String localPart) {
return new QName(IdentityCoreConstants.IDENTITY_DEFAULT_NAMESPACE, localPart);
}
}

@ -21,9 +21,17 @@ package org.wso2.carbon.device.mgt.oauth.extensions.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.CarbonUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @scr.component name="org.wso2.carbon.device.mgt.oauth.extensions" immediate="true"
@ -49,17 +57,51 @@ import org.wso2.carbon.user.core.service.RealmService;
public class OAuthExtensionServiceComponent {
private static final Log log = LogFactory.getLog(OAuthExtensionServiceComponent.class);
private static final String REPOSITORY = "repository";
private static final String CONFIGURATION = "conf";
private static final String APIM_CONF_FILE = "api-manager.xml";
@SuppressWarnings("unused")
protected void activate(ComponentContext componentContext) {
if(log.isDebugEnabled()){
if (log.isDebugEnabled()) {
log.debug("Starting OAuthExtensionBundle");
}
try {
APIManagerConfiguration configuration = new APIManagerConfiguration();
String filePath = new StringBuilder().
append(CarbonUtils.getCarbonHome()).
append(File.separator).
append(REPOSITORY).
append(File.separator).
append(CONFIGURATION).
append(File.separator).
append(APIM_CONF_FILE).toString();
configuration.load(filePath);
// loading white listed scopes
List<String> whiteList;
// Read scope whitelist from Configuration.
whiteList = configuration.getProperty(APIConstants.API_KEY_MANGER_SCOPE_WHITELIST);
// If whitelist is null, default scopes will be put.
if (whiteList == null) {
whiteList = new ArrayList<String>();
whiteList.add(APIConstants.OPEN_ID_SCOPE_NAME);
whiteList.add(APIConstants.DEVICE_SCOPE_PATTERN);
}
OAuthExtensionsDataHolder.getInstance().setWhitelistedScopes(whiteList);
} catch (APIManagementException e) {
log.error("Error occurred while loading APIM configurations", e);
}
}
@SuppressWarnings("unused")
protected void deactivate(ComponentContext componentContext) {
if(log.isDebugEnabled()){
if (log.isDebugEnabled()) {
log.debug("Stopping OAuthExtensionBundle");
}
}

@ -22,6 +22,8 @@ import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
import org.wso2.carbon.user.core.service.RealmService;
import java.util.List;
/**
* This holds the OSGi service references required for oauth extensions bundle.
*/
@ -30,6 +32,7 @@ public class OAuthExtensionsDataHolder {
private RealmService realmService;
private OAuth2TokenValidationService oAuth2TokenValidationService;
private PermissionManagerService permissionManagerService;
private List<String> whitelistedScopes;
private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder();
@ -72,4 +75,12 @@ public class OAuthExtensionsDataHolder {
}
return permissionManagerService;
}
public List<String> getWhitelistedScopes() {
return whitelistedScopes;
}
public void setWhitelistedScopes(List<String> whitelistedScopes) {
this.whitelistedScopes = whitelistedScopes;
}
}

Loading…
Cancel
Save