added PAP client in Airavata Server, which publishes and enables the default XACML authorization policy in the XACML authorization server, at the airavata server startup - if the security is enabled.
Project: http://git-wip-us.apache.org/repos/asf/airavata/repo Commit: http://git-wip-us.apache.org/repos/asf/airavata/commit/59f4acda Tree: http://git-wip-us.apache.org/repos/asf/airavata/tree/59f4acda Diff: http://git-wip-us.apache.org/repos/asf/airavata/diff/59f4acda Branch: refs/heads/master Commit: 59f4acda5c600cb7c11a645fba1bacb4bad27e16 Parents: c365260 Author: hasinitg <[email protected]> Authored: Sat Aug 8 01:21:08 2015 +0530 Committer: hasinitg <[email protected]> Committed: Sat Aug 8 01:21:08 2015 +0530 ---------------------------------------------------------------------- airavata-api/airavata-api-server/pom.xml | 5 + .../airavata/api/server/AiravataAPIServer.java | 10 ++ .../security/AiravataSecurityManager.java | 13 ++ .../DefaultAiravataSecurityManager.java | 56 ++++++++- .../api/server/security/DefaultPAPClient.java | 126 +++++++++++++++++++ .../api/server/security/DefaultXACMLPEP.java | 3 +- .../apache/airavata/common/utils/Constants.java | 2 + .../airavata/common/utils/ServerSettings.java | 6 +- .../resources/airavata-default-xacml-policy.xml | 2 +- .../main/resources/airavata-server.properties | 1 + 10 files changed, 219 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/pom.xml ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/pom.xml b/airavata-api/airavata-api-server/pom.xml index 543bbaa..e78ff9d 100644 --- a/airavata-api/airavata-api-server/pom.xml +++ b/airavata-api/airavata-api-server/pom.xml @@ -113,6 +113,11 @@ <version>4.2.1</version> </dependency> <dependency> + <groupId>org.wso2.carbon</groupId> + <artifactId>org.wso2.carbon.identity.entitlement.common</artifactId> + <version>4.2.1</version> + </dependency> + <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.0</version> http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/AiravataAPIServer.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/AiravataAPIServer.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/AiravataAPIServer.java index 1b336e1..c06cd39 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/AiravataAPIServer.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/AiravataAPIServer.java @@ -27,6 +27,8 @@ import java.net.InetAddress; import org.apache.airavata.api.Airavata; import org.apache.airavata.api.server.handler.AiravataServerHandler; +import org.apache.airavata.api.server.security.AiravataSecurityManager; +import org.apache.airavata.api.server.security.SecurityManagerFactory; import org.apache.airavata.api.server.security.SecurityModule; import org.apache.airavata.api.server.util.AppCatalogInitUtil; import org.apache.airavata.api.server.util.Constants; @@ -38,6 +40,7 @@ import org.apache.airavata.common.utils.IServer; import org.apache.airavata.common.utils.ServerSettings; import org.apache.airavata.model.error.AiravataErrorType; import org.apache.airavata.model.error.AiravataSystemException; +import org.apache.airavata.security.AiravataSecurityException; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.transport.TServerSocket; @@ -145,6 +148,10 @@ public class AiravataAPIServer implements IServer{ }.start(); logger.info("Airavata API server starter over TLS on Port: " + ServerSettings.getTLSServerPort()); } + //perform any security related initialization at the server startup, according to the security manager being used. + AiravataSecurityManager securityManager = SecurityManagerFactory.getSecurityManager(); + securityManager.initializeSecurityInfra(); + } catch (TTransportException e) { logger.error(e.getMessage()); setStatus(ServerStatus.FAILED); @@ -156,6 +163,9 @@ public class AiravataAPIServer implements IServer{ } catch (UnknownHostException e) { logger.error(e.getMessage(), e); throw new AiravataSystemException(AiravataErrorType.INTERNAL_ERROR); + } catch (AiravataSecurityException e) { + logger.error(e.getMessage(), e); + throw new AiravataSystemException(AiravataErrorType.INTERNAL_ERROR); } } public static void main(String[] args) { http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/AiravataSecurityManager.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/AiravataSecurityManager.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/AiravataSecurityManager.java index 37c348c..9245576 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/AiravataSecurityManager.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/AiravataSecurityManager.java @@ -26,5 +26,18 @@ import org.apache.airavata.security.AiravataSecurityException; import java.util.Map; public interface AiravataSecurityManager { + /** + * Implement this method in your SecurityManager to perform necessary initializations at the server startup. + * @throws AiravataSecurityException + */ + public void initializeSecurityInfra() throws AiravataSecurityException; + + /** + * Implement this method with the user authentication/authorization logic in your SecurityManager. + * @param authzToken : this includes OAuth token and user's claims + * @param metaData : this includes other meta data needed for security enforcements. + * @return + * @throws AiravataSecurityException + */ public boolean isUserAuthorized(AuthzToken authzToken, Map<String, String> metaData) throws AiravataSecurityException; } http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultAiravataSecurityManager.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultAiravataSecurityManager.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultAiravataSecurityManager.java index 6230310..532f9f6 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultAiravataSecurityManager.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultAiravataSecurityManager.java @@ -21,6 +21,7 @@ package org.apache.airavata.api.server.security; import org.apache.airavata.common.exception.ApplicationSettingsException; +import org.apache.airavata.common.utils.Constants; import org.apache.airavata.common.utils.ServerSettings; import org.apache.airavata.model.security.AuthzToken; import org.apache.airavata.security.AiravataSecurityException; @@ -32,6 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; +import java.io.*; import java.util.Map; /** @@ -40,6 +42,56 @@ import java.util.Map; public class DefaultAiravataSecurityManager implements AiravataSecurityManager { private final static Logger logger = LoggerFactory.getLogger(DefaultAiravataSecurityManager.class); + @Override + public void initializeSecurityInfra() throws AiravataSecurityException { + /* in the default security manager, this method checks if the xacml authorization policy is published, + * and if not, publish the policy to the PDP (of WSO2 Identity Server) + */ + try { + if (ServerSettings.isAPISecured()) { + + ConfigurationContext configContext = + ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null); + //initialize SSL context with the trust store that contains the public cert of WSO2 Identity Server. + TrustStoreManager trustStoreManager = new TrustStoreManager(); + trustStoreManager.initializeTrustStoreManager(ServerSettings.getTrustStorePath(), + ServerSettings.getTrustStorePassword()); + DefaultPAPClient PAPClient = new DefaultPAPClient(ServerSettings.getRemoteAuthzServerUrl(), + ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); + boolean policyAdded = PAPClient.isPolicyAdded(ServerSettings.getAuthorizationPoliyName()); + if (policyAdded) { + logger.info("Authorization policy is already added in the authorization server."); + } else { + //read the policy as a string + BufferedReader bufferedReader = new BufferedReader(new FileReader(new File( + ServerSettings.getAuthorizationPoliyName() + ".xml"))); + String line; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line); + } + //publish the policy and enable it in a separate thread + PAPClient.addPolicy(stringBuilder.toString()); + } + } + + } catch (AxisFault axisFault) { + logger.error(axisFault.getMessage(), axisFault); + throw new AiravataSecurityException("Error in initializing the configuration context for creating the " + + "PAP client."); + } catch (ApplicationSettingsException e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error in reading configuration when creating the PAP client."); + } catch (FileNotFoundException e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error in reading authorization policy."); + } catch (IOException e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error in reading the authorization policy."); + } + + } + public boolean isUserAuthorized(AuthzToken authzToken, Map<String, String> metaData) throws AiravataSecurityException { try { ConfigurationContext configContext = @@ -50,13 +102,13 @@ public class DefaultAiravataSecurityManager implements AiravataSecurityManager { trustStoreManager.initializeTrustStoreManager(ServerSettings.getTrustStorePath(), ServerSettings.getTrustStorePassword()); - DefaultOAuthClient oauthClient = new DefaultOAuthClient(ServerSettings.getRemoteOauthServerUrl(), + DefaultOAuthClient oauthClient = new DefaultOAuthClient(ServerSettings.getRemoteAuthzServerUrl(), ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); OAuth2TokenValidationResponseDTO validationResponse = oauthClient.validateAccessToken( authzToken.getAccessToken()); boolean isOAuthTokenValid = validationResponse.getValid(); //if XACML based authorization is enabled, check for role based authorization for the API invocation - DefaultXACMLPEP entitlementClient = new DefaultXACMLPEP(ServerSettings.getRemoteOauthServerUrl(), + DefaultXACMLPEP entitlementClient = new DefaultXACMLPEP(ServerSettings.getRemoteAuthzServerUrl(), ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); boolean authorizationDecision = entitlementClient.getAuthorizationDecision(authzToken, metaData); http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultPAPClient.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultPAPClient.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultPAPClient.java new file mode 100644 index 0000000..b75129c --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultPAPClient.java @@ -0,0 +1,126 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.api.server.security; + +import com.sun.corba.se.spi.activation.Server; +import org.apache.airavata.common.exception.ApplicationSettingsException; +import org.apache.airavata.common.utils.ServerSettings; +import org.apache.airavata.security.AiravataSecurityException; +import org.apache.axis2.AxisFault; +import org.apache.axis2.context.ConfigurationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.carbon.identity.entitlement.stub.EntitlementPolicyAdminServiceStub; +import org.wso2.carbon.identity.entitlement.stub.dto.PaginatedStatusHolder; +import org.wso2.carbon.identity.entitlement.stub.dto.PolicyDTO; +import org.wso2.carbon.identity.entitlement.stub.dto.StatusHolder; +import org.wso2.carbon.identity.entitlement.common.EntitlementConstants; +import org.wso2.carbon.identity.entitlement.stub.EntitlementPolicyAdminServiceEntitlementException; +import org.wso2.carbon.utils.CarbonUtils; + +import java.rmi.RemoteException; + +/** + * This publishes the airavata-default-xacml-policy.xml to the PDP via PAP API (of WSO2 Identity Server) + */ +public class DefaultPAPClient { + + private final static Logger logger = LoggerFactory.getLogger(DefaultPAPClient.class); + private EntitlementPolicyAdminServiceStub entitlementPolicyAdminServiceStub; + + public DefaultPAPClient(String auhorizationServerURL, String username, String password, + ConfigurationContext configCtx) throws AiravataSecurityException { + try { + + String PDPURL = auhorizationServerURL + "EntitlementPolicyAdminService"; + entitlementPolicyAdminServiceStub = new EntitlementPolicyAdminServiceStub(configCtx, PDPURL); + CarbonUtils.setBasicAccessSecurityHeaders(username, password, true, + entitlementPolicyAdminServiceStub._getServiceClient()); + } catch (AxisFault e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error initializing XACML PEP client."); + } + + } + + public boolean isPolicyAdded(String policyName) { + try { + PolicyDTO policyDTO = entitlementPolicyAdminServiceStub.getPolicy(policyName, false); + } catch (RemoteException e) { + logger.debug("Error in retrieving the policy.", e); + return false; + } catch (EntitlementPolicyAdminServiceEntitlementException e) { + logger.debug("Error in retrieving the policy.", e); + return false; + } + return true; + } + + public void addPolicy(String policy) throws AiravataSecurityException { + new Thread() { + public void run() { + try { + PolicyDTO policyDTO = new PolicyDTO(); + policyDTO.setPolicy(policy); + entitlementPolicyAdminServiceStub.addPolicy(policyDTO); + entitlementPolicyAdminServiceStub.publishToPDP(new String[]{ServerSettings.getAuthorizationPoliyName()}, + EntitlementConstants.PolicyPublish.ACTION_CREATE, null, false, 0); + + //Since policy publishing happens asynchronously, we need to retrieve the status and verify. + Thread.sleep(2000); + PaginatedStatusHolder paginatedStatusHolder = entitlementPolicyAdminServiceStub. + getStatusData(EntitlementConstants.Status.ABOUT_POLICY, ServerSettings.getAuthorizationPoliyName(), + EntitlementConstants.StatusTypes.PUBLISH_POLICY, "*", 1); + StatusHolder statusHolder = paginatedStatusHolder.getStatusHolders()[0]; + if (statusHolder.getSuccess() && EntitlementConstants.PolicyPublish.ACTION_CREATE.equals(statusHolder.getTargetAction())) { + logger.info("Authorization policy is published successfully."); + } else { + throw new AiravataSecurityException("Failed to publish the authorization policy."); + } + + //enable the published policy + entitlementPolicyAdminServiceStub.enableDisablePolicy(ServerSettings.getAuthorizationPoliyName(), true); + //Since policy enabling happens asynchronously, we need to retrieve the status and verify. + Thread.sleep(2000); + paginatedStatusHolder = entitlementPolicyAdminServiceStub. + getStatusData(EntitlementConstants.Status.ABOUT_POLICY, ServerSettings.getAuthorizationPoliyName(), + EntitlementConstants.StatusTypes.PUBLISH_POLICY, "*", 1); + statusHolder = paginatedStatusHolder.getStatusHolders()[0]; + if (statusHolder.getSuccess() && EntitlementConstants.PolicyPublish.ACTION_ENABLE.equals(statusHolder.getTargetAction())) { + logger.info("Authorization policy is enabled successfully."); + } else { + throw new AiravataSecurityException("Failed to enable the authorization policy."); + } + } catch (RemoteException e) { + logger.error(e.getMessage(), e); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } catch (ApplicationSettingsException e) { + logger.error(e.getMessage(), e); + } catch (AiravataSecurityException e) { + logger.error(e.getMessage(), e); + } catch (EntitlementPolicyAdminServiceEntitlementException e) { + logger.error(e.getMessage(), e); + } + } + }.start(); + } +} http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java index b60069c..71ced3a 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java @@ -47,7 +47,8 @@ import java.rmi.RemoteException; import java.util.Map; /** - * This enforces XACML based fine grained authorization on the API calls. + * This enforces XACML based fine grained authorization on the API calls, by authorizing the API calls + * through default PDP which is WSO2 Identity Server. */ public class DefaultXACMLPEP { http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/modules/commons/src/main/java/org/apache/airavata/common/utils/Constants.java ---------------------------------------------------------------------- diff --git a/modules/commons/src/main/java/org/apache/airavata/common/utils/Constants.java b/modules/commons/src/main/java/org/apache/airavata/common/utils/Constants.java index 215a313..af8ca96 100644 --- a/modules/commons/src/main/java/org/apache/airavata/common/utils/Constants.java +++ b/modules/commons/src/main/java/org/apache/airavata/common/utils/Constants.java @@ -50,6 +50,8 @@ public final class Constants { public static final String DENY = "Deny"; public static final String PERMIT = "Permit"; + public static final String AUTHORIZATION_POLICY_NAME = "authorization.policy"; + //Names of the attributes that could be passed in the AuthzToken's claims map. public static final String USER_NAME = "userName"; public static final String EMAIL = "email"; http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/modules/commons/src/main/java/org/apache/airavata/common/utils/ServerSettings.java ---------------------------------------------------------------------- diff --git a/modules/commons/src/main/java/org/apache/airavata/common/utils/ServerSettings.java b/modules/commons/src/main/java/org/apache/airavata/common/utils/ServerSettings.java index b898d96..d87da70 100644 --- a/modules/commons/src/main/java/org/apache/airavata/common/utils/ServerSettings.java +++ b/modules/commons/src/main/java/org/apache/airavata/common/utils/ServerSettings.java @@ -269,7 +269,7 @@ public class ServerSettings extends ApplicationSettings { return Boolean.valueOf(getSetting(Constants.IS_API_SECURED)); } - public static String getRemoteOauthServerUrl() throws ApplicationSettingsException { + public static String getRemoteAuthzServerUrl() throws ApplicationSettingsException { return getSetting(Constants.REMOTE_OAUTH_SERVER_URL); } @@ -281,6 +281,10 @@ public class ServerSettings extends ApplicationSettings { return getSetting(Constants.ADMIN_PASSWORD); } + public static String getAuthorizationPoliyName() throws ApplicationSettingsException{ + return getSetting(Constants.AUTHORIZATION_POLICY_NAME); + } + public static String getZookeeperConnection() throws ApplicationSettingsException { return getSetting(ZOOKEEPER_SERVER_CONNECTION, "localhost:2181"); } http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/modules/configuration/server/src/main/resources/airavata-default-xacml-policy.xml ---------------------------------------------------------------------- diff --git a/modules/configuration/server/src/main/resources/airavata-default-xacml-policy.xml b/modules/configuration/server/src/main/resources/airavata-default-xacml-policy.xml index b0ca91e..a8fbf4c 100644 --- a/modules/configuration/server/src/main/resources/airavata-default-xacml-policy.xml +++ b/modules/configuration/server/src/main/resources/airavata-default-xacml-policy.xml @@ -1,4 +1,4 @@ -<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="airavata-policy" +<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="airavata-default-xacml-policy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-overrides" Version="1.0"> <Target/> <Rule Effect="Permit" RuleId="admin-permit"> http://git-wip-us.apache.org/repos/asf/airavata/blob/59f4acda/modules/configuration/server/src/main/resources/airavata-server.properties ---------------------------------------------------------------------- diff --git a/modules/configuration/server/src/main/resources/airavata-server.properties b/modules/configuration/server/src/main/resources/airavata-server.properties index 0045935..58a42a3 100644 --- a/modules/configuration/server/src/main/resources/airavata-server.properties +++ b/modules/configuration/server/src/main/resources/airavata-server.properties @@ -237,5 +237,6 @@ keystore.password=airavata trust.store=client_truststore.jks trust.store.password=airavata remote.oauth.authorization.server=https://localhost:9443/services/ +authorization.policy=airavata-default-xacml-policy admin.user.name=admin admin.password=admin \ No newline at end of file
