mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Added OAuth scope validator & fixed DataHolders
This commit is contained in:
commit
648d8ec209
@ -36,6 +36,9 @@ public class APIPublisherDataHolder {
|
||||
}
|
||||
|
||||
public APIPublisherService getApiPublisherService() {
|
||||
if (apiPublisherService == null) {
|
||||
throw new IllegalStateException("APIPublisher service is not initialized properly");
|
||||
}
|
||||
return apiPublisherService;
|
||||
}
|
||||
|
||||
@ -48,6 +51,9 @@ public class APIPublisherDataHolder {
|
||||
}
|
||||
|
||||
public ConfigurationContextService getConfigurationContextService() {
|
||||
if (configurationContextService == null) {
|
||||
throw new IllegalStateException("ConfigurationContext service is not initialized properly");
|
||||
}
|
||||
return configurationContextService;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.device.mgt.common.permission.mgt;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* This class represents the information related to permission.
|
||||
*/
|
||||
@XmlRootElement (name = "Permission")
|
||||
public class Permission {
|
||||
|
||||
private String name; // permission name
|
||||
private String path; // permission string
|
||||
private String url; // url of the resource
|
||||
private String method; // http method
|
||||
private String scope; //scope of the resource
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@XmlElement (name = "name", required = true)
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@XmlElement (name = "path", required = true)
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
@XmlElement(name = "scope", required = true)
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@XmlElement (name = "url", required = true)
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@XmlElement (name = "method", required = true)
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.common.permission.mgt;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.device.mgt.common.permission.mgt;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* This represents the Permission management functionality which should be implemented by
|
||||
* required PermissionManagers.
|
||||
*/
|
||||
public interface PermissionManagerService {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param permission - Permission to be added
|
||||
* @return The status of the operation.
|
||||
* @throws PermissionManagementException If some unusual behaviour is observed while adding the
|
||||
* permission.
|
||||
*/
|
||||
public boolean addPermission(Permission permission) throws PermissionManagementException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param properties - Properties of the permission to be fetched.
|
||||
* @return The matched Permission object.
|
||||
* @throws PermissionManagementException If some unusual behaviour is observed while fetching the
|
||||
* permission.
|
||||
*/
|
||||
public Permission getPermission(Properties properties) throws PermissionManagementException;
|
||||
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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.device.mgt.core.config.permission;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement(name = "Permission")
|
||||
public class Permission{
|
||||
|
||||
private String name;
|
||||
private String path;
|
||||
private String scope;
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
@XmlElement(name = "scope", required = true)
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@XmlElement(name = "name", required = true)
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@XmlElement(name = "path", required = true)
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
@ -18,11 +18,16 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.core.config.permission;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.List;
|
||||
|
||||
@XmlRootElement(name = "PermissionConfiguration")
|
||||
/**
|
||||
* This class represents the information related to permission configuration.
|
||||
*/
|
||||
@XmlRootElement (name = "PermissionConfiguration")
|
||||
public class PermissionConfiguration {
|
||||
|
||||
private List<Permission> permissions;
|
||||
@ -31,7 +36,7 @@ public class PermissionConfiguration {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@XmlElement(name = "Permission", required = true)
|
||||
@XmlElement (name = "Permission", required = true)
|
||||
public void setPermissions(List<Permission> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.device.mgt.core.config.permission;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class will add, update custom permissions defined in permission.xml in webapps.
|
||||
*/
|
||||
public class PermissionManager {
|
||||
|
||||
private static PermissionManager permissionManager;
|
||||
|
||||
private PermissionManager(){};
|
||||
|
||||
public static PermissionManager getInstance() {
|
||||
if (permissionManager == null) {
|
||||
synchronized (PermissionManager.class) {
|
||||
if (permissionManager == null) {
|
||||
permissionManager = new PermissionManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return permissionManager;
|
||||
}
|
||||
|
||||
public boolean addPermission(Permission permission) throws DeviceManagementException {
|
||||
try {
|
||||
return PermissionUtils.putPermission(permission);
|
||||
} catch (DeviceManagementException e) {
|
||||
throw new DeviceManagementException("Error occurred while adding the permission : " +
|
||||
permission.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addPermissions(List<Permission> permissions) throws DeviceManagementException{
|
||||
for(Permission permission:permissions){
|
||||
this.addPermission(permission);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void initializePermissions(InputStream permissionStream) throws DeviceManagementException {
|
||||
try {
|
||||
if(permissionStream != null){
|
||||
/* Un-marshaling Device Management configuration */
|
||||
JAXBContext cdmContext = JAXBContext.newInstance(PermissionConfiguration.class);
|
||||
Unmarshaller unmarshaller = cdmContext.createUnmarshaller();
|
||||
PermissionConfiguration permissionConfiguration = (PermissionConfiguration)
|
||||
unmarshaller.unmarshal(permissionStream);
|
||||
if((permissionConfiguration != null) && (permissionConfiguration.getPermissions() != null)){
|
||||
this.addPermissions(permissionConfiguration.getPermissions());
|
||||
}
|
||||
}
|
||||
} catch (JAXBException e) {
|
||||
throw new DeviceManagementException("Error occurred while initializing Data Source config", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,11 +24,16 @@ 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.device.mgt.common.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.config.permission.PermissionManager;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.config.permission.PermissionConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.permission.mgt.RegistryBasedPermissionManagerServiceImpl;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class WebAppDeploymentLifecycleListener implements LifecycleListener {
|
||||
@ -42,12 +47,29 @@ public class WebAppDeploymentLifecycleListener implements LifecycleListener {
|
||||
StandardContext context = (StandardContext) lifecycleEvent.getLifecycle();
|
||||
ServletContext servletContext = context.getServletContext();
|
||||
try {
|
||||
PermissionManager.getInstance().initializePermissions(servletContext.getResourceAsStream(PERMISSION_CONFIG_PATH));
|
||||
} catch (DeviceManagementException e) {
|
||||
log.error("Exception occurred while adding the permissions from webapp : "
|
||||
+ servletContext.getContextPath(),e);
|
||||
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);
|
||||
if (permissionConfiguration != null &&
|
||||
permissionConfiguration.getPermissions() != null) {
|
||||
RegistryBasedPermissionManagerServiceImpl.getInstance().addPermissions(
|
||||
permissionConfiguration.getPermissions());
|
||||
}
|
||||
}
|
||||
} catch (JAXBException e) {
|
||||
log.error(
|
||||
"Exception occurred while parsing the permission configuration of webapp : "
|
||||
+ servletContext.getContextPath(), e);
|
||||
} catch (PermissionManagementException e) {
|
||||
log.error("Exception occurred while adding the permissions from webapp : "
|
||||
+ servletContext.getContextPath(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -51,6 +51,9 @@ public class DeviceManagementDataHolder {
|
||||
}
|
||||
|
||||
public RealmService getRealmService() {
|
||||
if (realmService == null) {
|
||||
throw new IllegalStateException("Realm service is not initialized properly");
|
||||
}
|
||||
return realmService;
|
||||
}
|
||||
|
||||
@ -79,6 +82,9 @@ public class DeviceManagementDataHolder {
|
||||
}
|
||||
|
||||
public RegistryService getRegistryService() {
|
||||
if (registryService == null) {
|
||||
throw new IllegalStateException("Registry service is not initialized properly");
|
||||
}
|
||||
return registryService;
|
||||
}
|
||||
|
||||
@ -127,6 +133,9 @@ public class DeviceManagementDataHolder {
|
||||
}
|
||||
|
||||
public ConfigurationContextService getConfigurationContextService() {
|
||||
if (configurationContextService == null) {
|
||||
throw new IllegalStateException("ConfigurationContext service is not initialized properly");
|
||||
}
|
||||
return configurationContextService;
|
||||
}
|
||||
|
||||
|
||||
@ -25,10 +25,10 @@ import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfigurationManagementService;
|
||||
import org.wso2.carbon.device.mgt.common.notification.mgt.Notification;
|
||||
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
|
||||
import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService;
|
||||
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
|
||||
import org.wso2.carbon.device.mgt.core.DeviceManagementPluginRepository;
|
||||
@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.core.notification.mgt.NotificationManagementSe
|
||||
import org.wso2.carbon.device.mgt.core.notification.mgt.dao.NotificationManagementDAOFactory;
|
||||
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationManagerImpl;
|
||||
import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory;
|
||||
import org.wso2.carbon.device.mgt.core.permission.mgt.RegistryBasedPermissionManagerServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.util.DeviceManagementSchemaInitializer;
|
||||
@ -188,6 +189,11 @@ public class DeviceManagementServiceComponent {
|
||||
= new NotificationManagementServiceImpl();
|
||||
bundleContext.registerService(NotificationManagementService.class.getName(), notificationManagementService, null);
|
||||
|
||||
/* Registering PermissionManager Service */
|
||||
PermissionManagerService permissionManagerService
|
||||
= RegistryBasedPermissionManagerServiceImpl.getInstance();
|
||||
bundleContext.registerService(PermissionManagerService.class.getName(), permissionManagerService, null);
|
||||
|
||||
/* Registering App Management service */
|
||||
try {
|
||||
AppManagementConfigurationManager.getInstance().initConfig();
|
||||
|
||||
@ -42,6 +42,9 @@ public class EmailServiceDataHolder {
|
||||
}
|
||||
|
||||
public ConfigurationContextService getConfigurationContextService() {
|
||||
if (configurationContextService == null) {
|
||||
throw new IllegalStateException("ConfigurationContext service is not initialized properly");
|
||||
}
|
||||
return configurationContextService;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.device.mgt.core.permission.mgt;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class represents the node of a permission tree.
|
||||
* It holds the current path name, list of permissions associated with URL
|
||||
* and the set of children.
|
||||
*/
|
||||
public class PermissionNode {
|
||||
|
||||
private String pathName;
|
||||
private Map<String, Permission> permissions = new HashMap<String, Permission>();
|
||||
private List<PermissionNode> children = new ArrayList<PermissionNode>();
|
||||
|
||||
public PermissionNode(String pathName) {
|
||||
this.pathName = pathName;
|
||||
}
|
||||
|
||||
public String getPathName() {
|
||||
return pathName;
|
||||
}
|
||||
|
||||
public void setPathName(String pathName) {
|
||||
this.pathName = pathName;
|
||||
}
|
||||
|
||||
public List<PermissionNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public PermissionNode getChild(String pathName) {
|
||||
PermissionNode child = null;
|
||||
for (PermissionNode node : children) {
|
||||
if (node.getPathName().equals(pathName)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
public void addChild(PermissionNode node) {
|
||||
children.add(node);
|
||||
}
|
||||
|
||||
public void addPermission(String httpMethod, Permission permission) {
|
||||
permissions.put(httpMethod, permission);
|
||||
}
|
||||
|
||||
public Permission getPermission(String httpMethod) {
|
||||
return permissions.get(httpMethod);
|
||||
}
|
||||
|
||||
public Collection<Permission> getPermissions() {
|
||||
return permissions.values();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.device.mgt.core.permission.mgt;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This class represents a tree data structure which will be used for adding and retrieving permissions.
|
||||
*/
|
||||
public class PermissionTree {
|
||||
|
||||
private PermissionNode rootNode;
|
||||
private static final String DYNAMIC_PATH_NOTATION = "*";
|
||||
private static final String ROOT = "/";
|
||||
private static final Log log = LogFactory.getLog(PermissionTree.class);
|
||||
|
||||
public PermissionTree() {
|
||||
rootNode = new PermissionNode(ROOT); // initializing the root node.
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to add permissions to the tree. Once it receives the permission
|
||||
* it will traverse through the given request path with respect to the permission and place
|
||||
* the permission in the appropriate place in the tree.
|
||||
*
|
||||
* @param permission Permission object.
|
||||
*/
|
||||
public void addPermission(Permission permission) {
|
||||
StringTokenizer st = new StringTokenizer(permission.getUrl(), ROOT);
|
||||
PermissionNode tempRoot = rootNode;
|
||||
PermissionNode tempChild;
|
||||
while (st.hasMoreTokens()) {
|
||||
tempChild = new PermissionNode(st.nextToken());
|
||||
tempRoot = addPermissionNode(tempRoot, tempChild);
|
||||
}
|
||||
tempRoot.addPermission(permission.getMethod(), permission); //setting permission to the vertex
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Added permission '" + permission.getName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to add vertex to the graph. The method will check for the given child
|
||||
* whether exists within the list of children of the given parent.
|
||||
*
|
||||
* @param parent Parent PermissionNode.
|
||||
* @param child Child PermissionNode.
|
||||
* @return returns the newly created child or the existing child.
|
||||
*/
|
||||
private PermissionNode addPermissionNode(PermissionNode parent, PermissionNode child) {
|
||||
PermissionNode existChild = parent.getChild(child.getPathName());
|
||||
if (existChild == null) {
|
||||
parent.addChild(child);
|
||||
return child;
|
||||
}
|
||||
return existChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to retrieve the permission for a given url and http method.
|
||||
* Breath First Search (BFS) is used to traverse the tree.
|
||||
*
|
||||
* @param url Request URL.
|
||||
* @param httpMethod HTTP method of the request.
|
||||
* @return returns the permission with related to the request path or null if there is
|
||||
* no any permission that is stored with respected to the given request path.
|
||||
*/
|
||||
public Permission getPermission(String url, String httpMethod) {
|
||||
StringTokenizer st = new StringTokenizer(url, ROOT);
|
||||
PermissionNode tempRoot = rootNode;
|
||||
while (st.hasMoreTokens()) {
|
||||
String currentToken = st.nextToken();
|
||||
|
||||
// returns the child node which matches with the 'currentToken' path.
|
||||
tempRoot = tempRoot.getChild(currentToken);
|
||||
|
||||
// if tempRoot is null, that means 'currentToken' is not matched with the child's path.
|
||||
// It means that it is at a point where the request must have dynamic path variables.
|
||||
// Therefor it looks for '*' in the request path. ('*' denotes dynamic path variable).
|
||||
if (tempRoot == null) {
|
||||
tempRoot = tempRoot.getChild(DYNAMIC_PATH_NOTATION);
|
||||
// if tempRoot is null, that means there is no any permission which matches with the
|
||||
// given path
|
||||
if (tempRoot == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Permission for request path '" + url + "' does not exist");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tempRoot.getPermission(httpMethod);
|
||||
}
|
||||
}
|
||||
@ -16,11 +16,13 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.device.mgt.core.config.permission;
|
||||
package org.wso2.carbon.device.mgt.core.permission.mgt;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
|
||||
import org.wso2.carbon.registry.api.RegistryException;
|
||||
import org.wso2.carbon.registry.api.Resource;
|
||||
@ -39,20 +41,20 @@ public class PermissionUtils {
|
||||
public static String ADMIN_PERMISSION_REGISTRY_PATH = "/permission/admin";
|
||||
public static String PERMISSION_PROPERTY_NAME = "name";
|
||||
|
||||
public static Registry getGovernanceRegistry() throws DeviceManagementException {
|
||||
public static Registry getGovernanceRegistry() throws PermissionManagementException {
|
||||
try {
|
||||
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
|
||||
return DeviceManagementDataHolder.getInstance().getRegistryService()
|
||||
.getGovernanceSystemRegistry(
|
||||
tenantId);
|
||||
} catch (RegistryException e) {
|
||||
throw new DeviceManagementException(
|
||||
throw new PermissionManagementException(
|
||||
"Error in retrieving governance registry instance: " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Permission getPermission(String path) throws DeviceManagementException {
|
||||
public static Permission getPermission(String path) throws PermissionManagementException {
|
||||
try {
|
||||
Resource resource = PermissionUtils.getGovernanceRegistry().get(path);
|
||||
Permission permission = new Permission();
|
||||
@ -60,13 +62,13 @@ public class PermissionUtils {
|
||||
permission.setPath(resource.getPath());
|
||||
return permission;
|
||||
} catch (RegistryException e) {
|
||||
throw new DeviceManagementException("Error in retrieving registry resource : " +
|
||||
throw new PermissionManagementException("Error in retrieving registry resource : " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean putPermission(Permission permission)
|
||||
throws DeviceManagementException {
|
||||
throws PermissionManagementException {
|
||||
boolean status;
|
||||
try {
|
||||
Resource resource = PermissionUtils.getGovernanceRegistry().newCollection();
|
||||
@ -77,27 +79,27 @@ public class PermissionUtils {
|
||||
PermissionUtils.getGovernanceRegistry().commitTransaction();
|
||||
status = true;
|
||||
} catch (RegistryException e) {
|
||||
throw new DeviceManagementException(
|
||||
throw new PermissionManagementException(
|
||||
"Error occurred while persisting permission : " +
|
||||
permission.getName(), e);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
public static boolean checkPermissionExistance(Permission permission)
|
||||
throws DeviceManagementException,
|
||||
public static boolean checkPermissionExistence(Permission permission)
|
||||
throws PermissionManagementException,
|
||||
org.wso2.carbon.registry.core.exceptions.RegistryException {
|
||||
return PermissionUtils.getGovernanceRegistry().resourceExists(permission.getPath());
|
||||
}
|
||||
|
||||
public static Document convertToDocument(File file) throws DeviceManagementException {
|
||||
public static Document convertToDocument(File file) throws PermissionManagementException {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
DocumentBuilder docBuilder = factory.newDocumentBuilder();
|
||||
return docBuilder.parse(file);
|
||||
} catch (Exception e) {
|
||||
throw new DeviceManagementException("Error occurred while parsing file, while converting " +
|
||||
throw new PermissionManagementException("Error occurred while parsing file, while converting " +
|
||||
"to a org.w3c.dom.Document", e);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.device.mgt.core.permission.mgt;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* This class will add, update custom permissions defined in permission.xml in webapps and it will
|
||||
* use Registry as the persistence storage.
|
||||
*/
|
||||
public class RegistryBasedPermissionManagerServiceImpl implements PermissionManagerService {
|
||||
|
||||
public static final String URL_PROPERTY = "URL";
|
||||
public static final String HTTP_METHOD_PROPERTY = "HTTP_METHOD";
|
||||
private static RegistryBasedPermissionManagerServiceImpl registryBasedPermissionManager;
|
||||
private static PermissionTree permissionTree; // holds the permissions at runtime.
|
||||
|
||||
private RegistryBasedPermissionManagerServiceImpl() {
|
||||
}
|
||||
|
||||
public static RegistryBasedPermissionManagerServiceImpl getInstance() {
|
||||
if (registryBasedPermissionManager == null) {
|
||||
synchronized (RegistryBasedPermissionManagerServiceImpl.class) {
|
||||
if (registryBasedPermissionManager == null) {
|
||||
registryBasedPermissionManager = new RegistryBasedPermissionManagerServiceImpl();
|
||||
permissionTree = new PermissionTree();
|
||||
}
|
||||
}
|
||||
}
|
||||
return registryBasedPermissionManager;
|
||||
}
|
||||
|
||||
public boolean addPermissions(List<Permission> permissions) throws PermissionManagementException {
|
||||
for (Permission permission : permissions) {
|
||||
this.addPermission(permission);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addPermission(Permission permission) throws PermissionManagementException {
|
||||
permissionTree.addPermission(permission); // adding a permission to the tree
|
||||
return PermissionUtils.putPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission getPermission(Properties properties) throws PermissionManagementException {
|
||||
String url = (String) properties.get(URL_PROPERTY);
|
||||
String httpMethod = (String) properties.get(HTTP_METHOD_PROPERTY);
|
||||
return permissionTree.getPermission(url, httpMethod);
|
||||
}
|
||||
}
|
||||
@ -34,6 +34,10 @@
|
||||
<url>http://wso2.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.identity</groupId>
|
||||
<artifactId>org.wso2.carbon.identity.oauth</artifactId>
|
||||
@ -68,7 +72,8 @@
|
||||
<Private-Package>org.wso2.carbon.device.mgt.oauth.extensions.internal</Private-Package>
|
||||
<Export-Package>
|
||||
!org.wso2.carbon.device.mgt.oauth.extensions.internal,
|
||||
org.wso2.carbon.device.mgt.oauth.extensions.*
|
||||
org.wso2.carbon.device.mgt.oauth.extensions.handlers.*,
|
||||
org.wso2.carbon.device.mgt.oauth.extensions.validators.*
|
||||
</Export-Package>
|
||||
<DynamicImport-Package>*</DynamicImport-Package>
|
||||
</instructions>
|
||||
|
||||
@ -55,6 +55,7 @@ public class DeviceMgtOAuthCallbackHandler extends AbstractOAuthCallbackHandler
|
||||
String[] scopes = oauthCallback.getRequestedScope();
|
||||
oauthCallback.setApprovedScope(scopes);
|
||||
oauthCallback.setValidScope(true);
|
||||
//TODO Need to write the necessary logic to validate the scope
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,8 @@ 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.device.mgt.common.permission.mgt.PermissionManagerService;
|
||||
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
|
||||
import org.wso2.carbon.user.core.service.RealmService;
|
||||
|
||||
/**
|
||||
@ -31,6 +33,18 @@ import org.wso2.carbon.user.core.service.RealmService;
|
||||
* policy="dynamic"
|
||||
* bind="setRealmService"
|
||||
* unbind="unsetRealmService"
|
||||
* @scr.reference name="identity.oauth2.validation.service"
|
||||
* interface="org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService"
|
||||
* cardinality="1..1"
|
||||
* policy="dynamic"
|
||||
* bind="setOAuth2ValidationService"
|
||||
* unbind="unsetOAuth2ValidationService"
|
||||
* @scr.reference name="permission.manager.service"
|
||||
* interface="org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService"
|
||||
* cardinality="1..1"
|
||||
* policy="dynamic"
|
||||
* bind="setPermissionManagerService"
|
||||
* unbind="unsetPermissionManagerService"
|
||||
*/
|
||||
public class OAuthExtensionServiceComponent {
|
||||
|
||||
@ -74,4 +88,52 @@ public class OAuthExtensionServiceComponent {
|
||||
OAuthExtensionsDataHolder.getInstance().setRealmService(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets OAuth2TokenValidation Service.
|
||||
*
|
||||
* @param tokenValidationService An instance of OAuth2TokenValidationService
|
||||
*/
|
||||
protected void setOAuth2ValidationService(OAuth2TokenValidationService tokenValidationService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Setting OAuth2TokenValidation Service");
|
||||
}
|
||||
OAuthExtensionsDataHolder.getInstance().setoAuth2TokenValidationService(tokenValidationService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets OAuth2TokenValidation Service.
|
||||
*
|
||||
* @param tokenValidationService An instance of OAuth2TokenValidationService
|
||||
*/
|
||||
protected void unsetOAuth2ValidationService(OAuth2TokenValidationService tokenValidationService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsetting OAuth2TokenValidation Service");
|
||||
}
|
||||
OAuthExtensionsDataHolder.getInstance().setoAuth2TokenValidationService(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets PermissionManagerService Service.
|
||||
*
|
||||
* @param permissionManagerService An instance of PermissionManagerService
|
||||
*/
|
||||
protected void setPermissionManagerService(PermissionManagerService permissionManagerService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Setting PermissionManager Service");
|
||||
}
|
||||
OAuthExtensionsDataHolder.getInstance().setPermissionManagerService(permissionManagerService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets PermissionManagerService Service.
|
||||
*
|
||||
* @param permissionManagerService An instance of PermissionManagerService
|
||||
*/
|
||||
protected void unsetPermissionManagerService(PermissionManagerService permissionManagerService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsetting PermissionManager Service");
|
||||
}
|
||||
OAuthExtensionsDataHolder.getInstance().setPermissionManagerService(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.oauth.extensions.internal;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -26,6 +28,8 @@ import org.wso2.carbon.user.core.service.RealmService;
|
||||
public class OAuthExtensionsDataHolder {
|
||||
|
||||
private RealmService realmService;
|
||||
private OAuth2TokenValidationService oAuth2TokenValidationService;
|
||||
private PermissionManagerService permissionManagerService;
|
||||
|
||||
private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder();
|
||||
|
||||
@ -36,10 +40,36 @@ public class OAuthExtensionsDataHolder {
|
||||
}
|
||||
|
||||
public RealmService getRealmService() {
|
||||
if (realmService == null) {
|
||||
throw new IllegalStateException("Realm service is not initialized properly");
|
||||
}
|
||||
return realmService;
|
||||
}
|
||||
|
||||
public void setRealmService(RealmService realmService) {
|
||||
this.realmService = realmService;
|
||||
}
|
||||
|
||||
public OAuth2TokenValidationService getoAuth2TokenValidationService() {
|
||||
if (oAuth2TokenValidationService == null) {
|
||||
throw new IllegalStateException("OAuth2TokenValidation service is not initialized properly");
|
||||
}
|
||||
return oAuth2TokenValidationService;
|
||||
}
|
||||
|
||||
public void setoAuth2TokenValidationService(
|
||||
OAuth2TokenValidationService oAuth2TokenValidationService) {
|
||||
this.oAuth2TokenValidationService = oAuth2TokenValidationService;
|
||||
}
|
||||
|
||||
public void setPermissionManagerService(PermissionManagerService permissionManagerService) {
|
||||
this.permissionManagerService = permissionManagerService;
|
||||
}
|
||||
|
||||
public PermissionManagerService getPermissionManagerService() {
|
||||
if (permissionManagerService == null) {
|
||||
throw new IllegalStateException("PermissionManager service is not initialized properly");
|
||||
}
|
||||
return permissionManagerService;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ public class OAuth2TokenValidator extends DefaultOAuth2TokenValidator {
|
||||
@Override
|
||||
public boolean validateAccessToken(
|
||||
OAuth2TokenValidationMessageContext validationReqDTO) throws IdentityOAuth2Exception {
|
||||
//for now there's no specific logic to handle in token validation
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,19 +18,67 @@
|
||||
|
||||
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.context.CarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
|
||||
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
|
||||
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
|
||||
import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
|
||||
import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator;
|
||||
import org.wso2.carbon.user.api.UserStoreException;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Created by harshan on 10/1/15.
|
||||
* Custom OAuth2Token Scope validation implementation.
|
||||
*/
|
||||
public class ScopeValidator extends OAuth2ScopeValidator {
|
||||
|
||||
private static final String URL_PROPERTY = "URL";
|
||||
private static final String HTTP_METHOD_PROPERTY = "HTTP_METHOD";
|
||||
|
||||
public static final class PermissionMethod {
|
||||
private PermissionMethod() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
public static final String READ = "read";
|
||||
public static final String WRITE = "write";
|
||||
public static final String DELETE = "delete";
|
||||
public static final String ACTION = "action";
|
||||
}
|
||||
|
||||
private static final Log log = LogFactory.getLog(ScopeValidator.class);
|
||||
|
||||
@Override
|
||||
public boolean validateScope(AccessTokenDO accessTokenDO, String resource)
|
||||
throws IdentityOAuth2Exception {
|
||||
//Call Milan's permission logic
|
||||
return true;
|
||||
boolean status = false;
|
||||
//Extract the url & http method
|
||||
int idx = resource.lastIndexOf(':');
|
||||
String url = resource.substring(0, idx);
|
||||
String method = resource.substring(++idx, resource.length());
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(ScopeValidator.URL_PROPERTY, url);
|
||||
properties.put(ScopeValidator.HTTP_METHOD_PROPERTY, method);
|
||||
PermissionManagerService permissionManagerService = OAuthExtensionsDataHolder.getInstance().
|
||||
getPermissionManagerService();
|
||||
try {
|
||||
Permission permission = permissionManagerService.getPermission(properties);
|
||||
String username = accessTokenDO.getAuthzUser();
|
||||
status = CarbonContext.getThreadLocalCarbonContext().getUserRealm().
|
||||
getAuthorizationManager().isUserAuthorized(username, permission.getPath(),
|
||||
ScopeValidator.PermissionMethod.READ);
|
||||
|
||||
} catch (PermissionManagementException e) {
|
||||
log.error("Error occurred while validating the resource scope for : " + resource +
|
||||
", Msg = " + e.getMessage(), e);
|
||||
} catch (UserStoreException e) {
|
||||
log.error("Error occurred while retrieving user store. " + e.getMessage());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
org.wso2.carbon.core.util,
|
||||
org.wso2.carbon.identity.base,
|
||||
org.wso2.carbon.identity.core.util,
|
||||
org.wso2.carbon.identity.oauth2.*,
|
||||
org.wso2.carbon.tomcat.ext.valves,
|
||||
org.wso2.carbon.user.api,
|
||||
org.wso2.carbon.user.core.service,
|
||||
@ -95,7 +96,9 @@
|
||||
org.wso2.carbon.apimgt.impl,
|
||||
org.wso2.carbon.certificate.mgt.core.service,
|
||||
org.wso2.carbon.certificate.mgt.core.exception,
|
||||
org.wso2.carbon.device.mgt.core.permission.mgt,
|
||||
org.wso2.carbon.device.mgt.common,
|
||||
org.wso2.carbon.device.mgt.common.permission.mgt,
|
||||
org.wso2.carbon.device.mgt.core.scep
|
||||
</Import-Package>
|
||||
<!--<Fragment-Host>tomcat</Fragment-Host>-->
|
||||
@ -142,6 +145,10 @@
|
||||
<groupId>org.wso2.carbon.identity</groupId>
|
||||
<artifactId>org.wso2.carbon.identity.core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.identity</groupId>
|
||||
<artifactId>org.wso2.carbon.identity.oauth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon</groupId>
|
||||
<artifactId>org.wso2.carbon.core.services</artifactId>
|
||||
|
||||
@ -29,6 +29,7 @@ import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.identity.base.IdentityException;
|
||||
import org.wso2.carbon.identity.core.util.IdentityUtil;
|
||||
import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
|
||||
@ -40,4 +40,14 @@ public final class Constants {
|
||||
public static final String CONTENT_TYPE_APPLICATION_XML = "application/xml";
|
||||
}
|
||||
|
||||
public static final class PermissionMethod {
|
||||
private PermissionMethod() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static final String READ = "read";
|
||||
public static final String WRITE = "write";
|
||||
public static final String DELETE = "delete";
|
||||
public static final String ACTION = "action";
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ package org.wso2.carbon.webapp.authenticator.framework;
|
||||
|
||||
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService;
|
||||
import org.wso2.carbon.device.mgt.core.scep.SCEPManager;
|
||||
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
|
||||
import org.wso2.carbon.user.core.service.RealmService;
|
||||
|
||||
public class DataHolder {
|
||||
@ -28,6 +29,8 @@ public class DataHolder {
|
||||
private RealmService realmService;
|
||||
private CertificateManagementService certificateManagementService;
|
||||
private SCEPManager scepManager;
|
||||
private OAuth2TokenValidationService oAuth2TokenValidationService;
|
||||
|
||||
private static DataHolder thisInstance = new DataHolder();
|
||||
|
||||
private DataHolder() {}
|
||||
@ -45,6 +48,9 @@ public class DataHolder {
|
||||
}
|
||||
|
||||
public RealmService getRealmService() {
|
||||
if (realmService == null) {
|
||||
throw new IllegalStateException("Realm service is not initialized properly");
|
||||
}
|
||||
return realmService;
|
||||
}
|
||||
|
||||
@ -53,6 +59,9 @@ public class DataHolder {
|
||||
}
|
||||
|
||||
public CertificateManagementService getCertificateManagementService() {
|
||||
if (certificateManagementService == null) {
|
||||
throw new IllegalStateException("CertificateManagement service is not initialized properly");
|
||||
}
|
||||
return certificateManagementService;
|
||||
}
|
||||
|
||||
@ -61,10 +70,25 @@ public class DataHolder {
|
||||
}
|
||||
|
||||
public SCEPManager getScepManager() {
|
||||
if (scepManager == null) {
|
||||
throw new IllegalStateException("SCEPManager service is not initialized properly");
|
||||
}
|
||||
return scepManager;
|
||||
}
|
||||
|
||||
public void setScepManager(SCEPManager scepManager) {
|
||||
this.scepManager = scepManager;
|
||||
}
|
||||
|
||||
public OAuth2TokenValidationService getoAuth2TokenValidationService() {
|
||||
if (oAuth2TokenValidationService == null) {
|
||||
throw new IllegalStateException("OAuth2TokenValidation service is not initialized properly");
|
||||
}
|
||||
return oAuth2TokenValidationService;
|
||||
}
|
||||
|
||||
public void setoAuth2TokenValidationService(
|
||||
OAuth2TokenValidationService oAuth2TokenValidationService) {
|
||||
this.oAuth2TokenValidationService = oAuth2TokenValidationService;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,12 +24,16 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
import org.wso2.carbon.apimgt.api.APIManagementException;
|
||||
import org.wso2.carbon.apimgt.core.authenticate.APITokenValidator;
|
||||
import org.wso2.carbon.apimgt.core.gateway.APITokenAuthenticator;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.identity.base.IdentityException;
|
||||
import org.wso2.carbon.identity.core.util.IdentityUtil;
|
||||
import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO;
|
||||
import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationException;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationFrameworkUtil;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.Constants;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.DataHolder;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
@ -40,6 +44,8 @@ public class OAuthAuthenticator implements WebappAuthenticator {
|
||||
private static final String OAUTH_AUTHENTICATOR = "OAuth";
|
||||
private static final String REGEX_BEARER_PATTERN = "[B|b]earer\\s";
|
||||
private static final Pattern PATTERN = Pattern.compile(REGEX_BEARER_PATTERN);
|
||||
private static final String BEARER_TOKEN_TYPE = "bearer";
|
||||
private static final String RESOURCE_KEY = "resource";
|
||||
|
||||
private static APITokenAuthenticator authenticator = new APITokenAuthenticator();
|
||||
|
||||
@ -66,6 +72,7 @@ public class OAuthAuthenticator implements WebappAuthenticator {
|
||||
@Override
|
||||
public Status authenticate(Request request, Response response) {
|
||||
String requestUri = request.getRequestURI();
|
||||
String requestMethod = request.getMethod();
|
||||
if (requestUri == null || "".equals(requestUri)) {
|
||||
return Status.CONTINUE;
|
||||
}
|
||||
@ -76,29 +83,59 @@ public class OAuthAuthenticator implements WebappAuthenticator {
|
||||
return Status.CONTINUE;
|
||||
}
|
||||
String apiVersion = tokenizer.nextToken();
|
||||
String domain = request.getHeader(APITokenValidator.getAPIManagerClientDomainHeader());
|
||||
String authLevel = authenticator.getResourceAuthenticationScheme(context, apiVersion,
|
||||
request.getRequestURI(), request.getMethod());
|
||||
|
||||
requestUri,
|
||||
requestMethod);
|
||||
try {
|
||||
if (Constants.NO_MATCHING_AUTH_SCHEME.equals(authLevel)) {
|
||||
AuthenticationFrameworkUtil.handleNoMatchAuthScheme(request, response, request.getMethod(),
|
||||
AuthenticationFrameworkUtil
|
||||
.handleNoMatchAuthScheme(request, response, requestMethod,
|
||||
apiVersion, context);
|
||||
return Status.CONTINUE;
|
||||
} else {
|
||||
String bearerToken = this.getBearerToken(request);
|
||||
boolean isAuthenticated =
|
||||
AuthenticationFrameworkUtil.doAuthenticate(context, apiVersion,
|
||||
bearerToken, authLevel, domain);
|
||||
// Create a OAuth2TokenValidationRequestDTO object for validating access token
|
||||
OAuth2TokenValidationRequestDTO dto = new OAuth2TokenValidationRequestDTO();
|
||||
//Set the access token info
|
||||
OAuth2TokenValidationRequestDTO.OAuth2AccessToken oAuth2AccessToken =
|
||||
dto.new OAuth2AccessToken();
|
||||
oAuth2AccessToken.setTokenType(OAuthAuthenticator.BEARER_TOKEN_TYPE);
|
||||
oAuth2AccessToken.setIdentifier(bearerToken);
|
||||
dto.setAccessToken(oAuth2AccessToken);
|
||||
//Set the resource context param. This will be used in scope validation.
|
||||
OAuth2TokenValidationRequestDTO.TokenValidationContextParam
|
||||
resourceContextParam = dto.new TokenValidationContextParam();
|
||||
resourceContextParam.setKey(OAuthAuthenticator.RESOURCE_KEY);
|
||||
resourceContextParam.setValue(requestUri + ":" + requestMethod);
|
||||
|
||||
OAuth2TokenValidationRequestDTO.TokenValidationContextParam []
|
||||
tokenValidationContextParams = new OAuth2TokenValidationRequestDTO.TokenValidationContextParam[1];
|
||||
tokenValidationContextParams[0] = resourceContextParam;
|
||||
dto.setContext(tokenValidationContextParams);
|
||||
|
||||
OAuth2TokenValidationResponseDTO oAuth2TokenValidationResponseDTO =
|
||||
DataHolder.getInstance().
|
||||
getoAuth2TokenValidationService().validate(dto);
|
||||
if (oAuth2TokenValidationResponseDTO.isValid()) {
|
||||
String username = oAuth2TokenValidationResponseDTO.getAuthorizedUser();
|
||||
try {
|
||||
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(
|
||||
IdentityUtil.getTenantIdOFUser(username));
|
||||
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
|
||||
} catch (IdentityException e) {
|
||||
throw new AuthenticationException(
|
||||
"Error occurred while retrieving the tenant ID of user '" +
|
||||
username + "'", e);
|
||||
}
|
||||
boolean isAuthenticated = oAuth2TokenValidationResponseDTO.isValid();
|
||||
return (isAuthenticated) ? Status.SUCCESS : Status.FAILURE;
|
||||
}
|
||||
} catch (APIManagementException e) {
|
||||
log.error("Error occurred while key validation", e);
|
||||
return Status.FAILURE;
|
||||
}
|
||||
} catch (AuthenticationException e) {
|
||||
log.error("Failed to authenticate the incoming request", e);
|
||||
return Status.FAILURE;
|
||||
}
|
||||
return Status.FAILURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.webapp.authenticator.framework.authorizer;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve;
|
||||
import org.wso2.carbon.tomcat.ext.valves.CompositeValve;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationFrameworkUtil;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class PermissionAuthorizationValve extends CarbonTomcatValve {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PermissionAuthorizationValve.class);
|
||||
private static final String AUTHORIZATION_ENABLED = "authorization-enabled";
|
||||
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response, CompositeValve compositeValve) {
|
||||
|
||||
String permissionStatus =
|
||||
request.getContext().findParameter(AUTHORIZATION_ENABLED);
|
||||
if (permissionStatus == null || permissionStatus.isEmpty()) {
|
||||
this.processResponse(request, response, compositeValve, WebappAuthenticator.Status.CONTINUE);
|
||||
return;
|
||||
}
|
||||
// check whether the permission checking function is enabled in web.xml
|
||||
boolean isEnabled = new Boolean(permissionStatus);
|
||||
if (!isEnabled) {
|
||||
this.processResponse(request, response, compositeValve, WebappAuthenticator.Status.CONTINUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Checking permission of request: " + request.getRequestURI());
|
||||
}
|
||||
PermissionAuthorizer permissionAuthorizer = new PermissionAuthorizer();
|
||||
WebappAuthenticator.Status status = permissionAuthorizer.authorize(request, response);
|
||||
this.processResponse(request, response, compositeValve, status);
|
||||
}
|
||||
|
||||
private void processResponse(Request request, Response response, CompositeValve compositeValve,
|
||||
WebappAuthenticator.Status status) {
|
||||
switch (status) {
|
||||
case SUCCESS:
|
||||
case CONTINUE:
|
||||
this.getNext().invoke(request, response, compositeValve);
|
||||
break;
|
||||
case FAILURE:
|
||||
String msg = "Failed to authorize incoming request";
|
||||
log.error(msg);
|
||||
AuthenticationFrameworkUtil.handleResponse(request, response, HttpServletResponse.SC_UNAUTHORIZED, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.webapp.authenticator.framework.authorizer;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.context.CarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.Permission;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.permission.mgt.RegistryBasedPermissionManagerServiceImpl;
|
||||
import org.wso2.carbon.user.api.UserStoreException;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.Constants;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* This class represents the methods that are used to authorize requests.
|
||||
*/
|
||||
public class PermissionAuthorizer {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PermissionAuthorizer.class);
|
||||
|
||||
public WebappAuthenticator.Status authorize(Request request, Response response) {
|
||||
|
||||
String requestUri = request.getRequestURI();
|
||||
String requestMethod = request.getMethod();
|
||||
|
||||
if (requestUri == null || requestUri.isEmpty() ||
|
||||
requestMethod == null || requestMethod.isEmpty()) {
|
||||
return WebappAuthenticator.Status.CONTINUE;
|
||||
}
|
||||
|
||||
RegistryBasedPermissionManagerServiceImpl registryBasedPermissionManager = RegistryBasedPermissionManagerServiceImpl.getInstance();
|
||||
Properties properties = new Properties();
|
||||
properties.put("",requestUri);
|
||||
properties.put("",requestMethod);
|
||||
Permission requestPermission = null;
|
||||
try {
|
||||
requestPermission = registryBasedPermissionManager.getPermission(properties);
|
||||
} catch (PermissionManagementException e) {
|
||||
log.error(
|
||||
"Error occurred while fetching the permission for URI : " + requestUri + " ," +
|
||||
" METHOD : " + requestMethod + ", msg = " + e.getMessage());
|
||||
}
|
||||
|
||||
if (requestPermission == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Permission to request '" + requestUri + "' is not defined in the configuration");
|
||||
}
|
||||
return WebappAuthenticator.Status.FAILURE;
|
||||
}
|
||||
|
||||
String permissionString = requestPermission.getPath();
|
||||
|
||||
// This is added temporarily until authentication works.
|
||||
// TODO remove below line.
|
||||
String username = "admin";
|
||||
// TODO uncomment this once the authentication works.
|
||||
//String username = CarbonContext.getThreadLocalCarbonContext().getUsername();
|
||||
|
||||
boolean isUserAuthorized;
|
||||
try {
|
||||
isUserAuthorized = CarbonContext.getThreadLocalCarbonContext().getUserRealm().
|
||||
getAuthorizationManager().isUserAuthorized(username, permissionString,
|
||||
Constants.PermissionMethod.READ);
|
||||
} catch (UserStoreException e) {
|
||||
log.error("Error occurred while retrieving user store. " + e.getMessage());
|
||||
return WebappAuthenticator.Status.FAILURE;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Is user authorized: " + isUserAuthorized);
|
||||
}
|
||||
|
||||
if (isUserAuthorized) {
|
||||
return WebappAuthenticator.Status.SUCCESS;
|
||||
} else {
|
||||
return WebappAuthenticator.Status.FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,14 +23,15 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService;
|
||||
import org.wso2.carbon.device.mgt.core.scep.SCEPManager;
|
||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
||||
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
|
||||
import org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve;
|
||||
import org.wso2.carbon.tomcat.ext.valves.TomcatValveContainer;
|
||||
import org.wso2.carbon.user.core.service.RealmService;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.DataHolder;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticationHandler;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticatorRepository;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticatorRepository;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.authorizer.PermissionAuthorizationValve;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.config.AuthenticatorConfig;
|
||||
import org.wso2.carbon.webapp.authenticator.framework.config.WebappAuthenticatorConfig;
|
||||
|
||||
@ -58,6 +59,12 @@ import java.util.List;
|
||||
* cardinality="1..n"
|
||||
* bind="setSCEPManagementService"
|
||||
* unbind="unsetSCEPManagementService"
|
||||
* @scr.reference name="identity.oauth2.validation.service"
|
||||
* interface="org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService"
|
||||
* cardinality="1..1"
|
||||
* policy="dynamic"
|
||||
* bind="setOAuth2ValidationService"
|
||||
* unbind="unsetOAuth2ValidationService"
|
||||
*/
|
||||
public class WebappAuthenticatorFrameworkServiceComponent {
|
||||
|
||||
@ -80,6 +87,7 @@ public class WebappAuthenticatorFrameworkServiceComponent {
|
||||
|
||||
List<CarbonTomcatValve> valves = new ArrayList<CarbonTomcatValve>();
|
||||
valves.add(new WebappAuthenticationHandler());
|
||||
//valves.add(new PermissionAuthorizationValve());
|
||||
TomcatValveContainer.addValves(valves);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
@ -135,4 +143,28 @@ public class WebappAuthenticatorFrameworkServiceComponent {
|
||||
|
||||
DataHolder.getInstance().setScepManager(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets OAuth2TokenValidation Service.
|
||||
*
|
||||
* @param tokenValidationService An instance of OAuth2TokenValidationService
|
||||
*/
|
||||
protected void setOAuth2ValidationService(OAuth2TokenValidationService tokenValidationService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Setting OAuth2TokenValidationService Service");
|
||||
}
|
||||
DataHolder.getInstance().setoAuth2TokenValidationService(tokenValidationService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets OAuth2TokenValidation Service.
|
||||
*
|
||||
* @param tokenValidationService An instance of OAuth2TokenValidationService
|
||||
*/
|
||||
protected void unsetOAuth2ValidationService(OAuth2TokenValidationService tokenValidationService) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsetting OAuth2TokenValidationService Service");
|
||||
}
|
||||
DataHolder.getInstance().setoAuth2TokenValidationService(null);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user