Adding the Authorization caching implementation. This completes the security solution implementation in the Airavata source code.
Project: http://git-wip-us.apache.org/repos/asf/airavata/repo Commit: http://git-wip-us.apache.org/repos/asf/airavata/commit/27774766 Tree: http://git-wip-us.apache.org/repos/asf/airavata/tree/27774766 Diff: http://git-wip-us.apache.org/repos/asf/airavata/diff/27774766 Branch: refs/heads/master Commit: 27774766f502f2e62c288c5bce0f8980926a7741 Parents: 59f4acd Author: hasinitg <[email protected]> Authored: Sun Aug 16 09:39:56 2015 -0400 Committer: hasinitg <[email protected]> Committed: Sun Aug 16 09:39:56 2015 -0400 ---------------------------------------------------------------------- .../airavata/api/server/AiravataAPIServer.java | 7 +- .../server/handler/AiravataServerHandler.java | 5 +- .../DefaultAiravataSecurityManager.java | 102 +++++++++++--- .../api/server/security/DefaultOAuthClient.java | 98 -------------- .../api/server/security/DefaultPAPClient.java | 126 ------------------ .../api/server/security/DefaultXACMLPEP.java | 132 ------------------- .../api/server/security/SecurityCheck.java | 36 ----- .../server/security/SecurityInterceptor.java | 84 ------------ .../server/security/SecurityManagerFactory.java | 7 +- .../api/server/security/SecurityModule.java | 39 ------ .../server/security/authzcache/AuthzCache.java | 61 +++++++++ .../security/authzcache/AuthzCachedStatus.java | 34 +++++ .../security/interceptor/SecurityCheck.java | 36 +++++ .../interceptor/SecurityInterceptor.java | 83 ++++++++++++ .../security/interceptor/SecurityModule.java | 41 ++++++ .../security/oauth/DefaultOAuthClient.java | 94 +++++++++++++ .../server/security/xacml/DefaultPAPClient.java | 125 ++++++++++++++++++ .../apache/airavata/common/utils/Constants.java | 7 + .../airavata/common/utils/ServerSettings.java | 82 +++++++----- .../main/resources/airavata-server.properties | 10 ++ 20 files changed, 629 insertions(+), 580 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/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 c06cd39..ca4e345 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 @@ -29,13 +29,11 @@ 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.security.interceptor.SecurityModule; import org.apache.airavata.api.server.util.AppCatalogInitUtil; import org.apache.airavata.api.server.util.Constants; import org.apache.airavata.api.server.util.RegistryInitUtil; import org.apache.airavata.common.exception.ApplicationSettingsException; -import org.apache.airavata.common.utils.AiravataUtils; -import org.apache.airavata.common.utils.AiravataZKUtils; import org.apache.airavata.common.utils.IServer; import org.apache.airavata.common.utils.ServerSettings; import org.apache.airavata.model.error.AiravataErrorType; @@ -148,7 +146,8 @@ 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. + /*perform any security related initialization at the server startup, according to the underlying security + manager implementation being used.*/ AiravataSecurityManager securityManager = SecurityManagerFactory.getSecurityManager(); securityManager.initializeSecurityInfra(); http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/handler/AiravataServerHandler.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/handler/AiravataServerHandler.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/handler/AiravataServerHandler.java index 600c694..7531fae 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/handler/AiravataServerHandler.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/handler/AiravataServerHandler.java @@ -23,9 +23,7 @@ package org.apache.airavata.api.server.handler; import org.apache.airavata.api.Airavata; import org.apache.airavata.api.airavataAPIConstants; -import org.apache.airavata.api.server.security.AiravataSecurityManager; -import org.apache.airavata.api.server.security.SecurityCheck; -import org.apache.airavata.api.server.security.SecurityManagerFactory; +import org.apache.airavata.api.server.security.interceptor.SecurityCheck; import org.apache.airavata.common.exception.AiravataException; import org.apache.airavata.common.exception.ApplicationSettingsException; import org.apache.airavata.common.utils.AiravataUtils; @@ -105,7 +103,6 @@ import org.apache.airavata.registry.cpi.RegistryException; import org.apache.airavata.registry.cpi.ResultOrderType; import org.apache.airavata.registry.cpi.WorkflowCatalog; import org.apache.airavata.registry.cpi.utils.Constants; -import org.apache.airavata.security.AiravataSecurityException; import org.apache.thrift.TException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/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 532f9f6..f42d98d 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 @@ -20,6 +20,10 @@ */ package org.apache.airavata.api.server.security; +import org.apache.airavata.api.server.security.authzcache.*; +import org.apache.airavata.api.server.security.oauth.DefaultOAuthClient; +import org.apache.airavata.api.server.security.xacml.DefaultPAPClient; +import org.apache.airavata.api.server.security.xacml.DefaultXACMLPEP; import org.apache.airavata.common.exception.ApplicationSettingsException; import org.apache.airavata.common.utils.Constants; import org.apache.airavata.common.utils.ServerSettings; @@ -72,6 +76,7 @@ public class DefaultAiravataSecurityManager implements AiravataSecurityManager { } //publish the policy and enable it in a separate thread PAPClient.addPolicy(stringBuilder.toString()); + logger.info("Authorization policy is published in the authorization server."); } } @@ -94,25 +99,84 @@ public class DefaultAiravataSecurityManager implements AiravataSecurityManager { public boolean isUserAuthorized(AuthzToken authzToken, Map<String, String> metaData) throws AiravataSecurityException { try { - 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()); - - 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.getRemoteAuthzServerUrl(), - ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); - boolean authorizationDecision = entitlementClient.getAuthorizationDecision(authzToken, metaData); - - return (isOAuthTokenValid && authorizationDecision); + //if the authz cache is enabled, check in the cache if the authz decision is cached and if so, what the status is + if (ServerSettings.isAuthzCacheEnabled()) { + //obtain an instance of AuthzCacheManager implementation. + AuthzCacheManager authzCacheManager = AuthzCacheManagerFactory.getAuthzCacheManager(); + //collect the necessary info for contructing the authz cache index + String subject = authzToken.getClaimsMap().get(Constants.USER_NAME); + String accessToken = authzToken.getAccessToken(); + String action = metaData.get(Constants.API_METHOD_NAME); + //check in the cache + AuthzCachedStatus authzCachedStatus = authzCacheManager.getAuthzCachedStatus( + new AuthzCacheIndex(subject, accessToken, action)); + + if (AuthzCachedStatus.AUTHORIZED.equals(authzCachedStatus)) { + //TODO: following info log is for demonstration purpose. change it to debug log. + logger.info("Authz decision for: (" + subject + ", " + accessToken + ", " + action + ") is retrieved from cache."); + return true; + } else if (AuthzCachedStatus.NOT_AUTHORIZED.equals(authzCachedStatus)) { + //TODO: following info log is for demonstration purpose. change it to debug log. + logger.info("Authz decision for: (" + subject + ", " + accessToken + ", " + action + ") is retrieved from cache."); + return false; + } else if (AuthzCachedStatus.NOT_CACHED.equals(authzCachedStatus)) { + //TODO: following info log is for demonstration purpose. change it to debug log. + logger.info("Authz decision for: (" + subject + ", " + accessToken + ", " + action + ") is not in the cache. " + + "Obtaining it from the authorization server."); + //talk to Authorization Server, obtain the decision, cache it and return the result. + 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()); + + DefaultOAuthClient oauthClient = new DefaultOAuthClient(ServerSettings.getRemoteAuthzServerUrl(), + ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); + OAuth2TokenValidationResponseDTO validationResponse = oauthClient.validateAccessToken( + authzToken.getAccessToken()); + boolean isOAuthTokenValid = validationResponse.getValid(); + long expiryTimestamp = validationResponse.getExpiryTime(); + + //check for fine grained authorization for the API invocation, based on XACML. + DefaultXACMLPEP entitlementClient = new DefaultXACMLPEP(ServerSettings.getRemoteAuthzServerUrl(), + ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); + boolean authorizationDecision = entitlementClient.getAuthorizationDecision(authzToken, metaData); + + boolean decision = isOAuthTokenValid && authorizationDecision; + + //cache the authorization decision + authzCacheManager.addToAuthzCache(new AuthzCacheIndex(subject, accessToken, action), + new AuthzCacheEntry(decision, expiryTimestamp)); + + return decision; + } else { + //undefined status returned from the authz cache manager + throw new AiravataSecurityException("Error in reading from the authorization cache."); + } + } else { + //talk to Authorization Server, obtain the decision and return the result (authz cache is not enabled). + 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()); + + 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.getRemoteAuthzServerUrl(), + ServerSettings.getAdminUsername(), ServerSettings.getAdminPassword(), configContext); + boolean authorizationDecision = entitlementClient.getAuthorizationDecision(authzToken, metaData); + + return (isOAuthTokenValid && authorizationDecision); + } } catch (AxisFault axisFault) { logger.error(axisFault.getMessage(), axisFault); http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultOAuthClient.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultOAuthClient.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultOAuthClient.java deleted file mode 100644 index e1afacd..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultOAuthClient.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * 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 org.apache.airavata.common.exception.ApplicationSettingsException; -import org.apache.airavata.common.utils.ServerSettings; -import org.apache.airavata.security.AiravataSecurityException; -import org.apache.airavata.security.util.TrustStoreManager; -import org.apache.axis2.AxisFault; -import org.apache.axis2.context.ConfigurationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub; -import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO; -import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken; -import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; -import org.wso2.carbon.utils.CarbonUtils; - -import javax.net.ssl.*; -import java.rmi.RemoteException; - -/** - * This is the default OAuth Client that talks to WSO2 IS's OAuth Authentication Server - * to get the OAuth token validated. - */ -public class DefaultOAuthClient { - - private OAuth2TokenValidationServiceStub stub; - private final static Logger logger = LoggerFactory.getLogger(DefaultOAuthClient.class); - public static final String BEARER_TOKEN_TYPE = "bearer"; - - /** - * OAuth2TokenValidationService Admin Service Client - * - * @param auhorizationServerURL - * @param username - * @param password - * @param configCtx - * @throws Exception - */ - public DefaultOAuthClient(String auhorizationServerURL, String username, String password, - ConfigurationContext configCtx) throws AiravataSecurityException { - try { - String serviceURL = auhorizationServerURL + "OAuth2TokenValidationService"; - stub = new OAuth2TokenValidationServiceStub(configCtx, serviceURL); - CarbonUtils.setBasicAccessSecurityHeaders(username, password, true, stub._getServiceClient()); - } catch (AxisFault e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error initializing OAuth client."); - } - } - - /** - * Validates the OAuth 2.0 access token - * - * @param accessToken - * @return - * @throws Exception - */ - public OAuth2TokenValidationResponseDTO validateAccessToken(String accessToken) - throws AiravataSecurityException { - - try { - OAuth2TokenValidationRequestDTO oauthReq = new OAuth2TokenValidationRequestDTO(); - OAuth2TokenValidationRequestDTO_OAuth2AccessToken token = - new OAuth2TokenValidationRequestDTO_OAuth2AccessToken(); - token.setIdentifier(accessToken); - token.setTokenType(BEARER_TOKEN_TYPE); - oauthReq.setAccessToken(token); - return stub.validate(oauthReq); - } catch (RemoteException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in validating the OAuth access token."); - } /*catch (ApplicationSettingsException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in reading OAuth configuration."); - }*/ - } - -} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/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 deleted file mode 100644 index b75129c..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultPAPClient.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * 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/27774766/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 deleted file mode 100644 index 71ced3a..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/DefaultXACMLPEP.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * 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 org.apache.airavata.common.utils.Constants; -import org.apache.airavata.model.security.AuthzToken; -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.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.wso2.carbon.identity.entitlement.stub.EntitlementServiceStub; -import org.wso2.carbon.identity.entitlement.stub.EntitlementServiceException; -import org.wso2.carbon.utils.CarbonUtils; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.util.Map; - -/** - * 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 { - - private final static Logger logger = LoggerFactory.getLogger(DefaultXACMLPEP.class); - private EntitlementServiceStub entitlementServiceStub; - - public DefaultXACMLPEP(String auhorizationServerURL, String username, String password, - ConfigurationContext configCtx) throws AiravataSecurityException { - try { - - String PDPURL = auhorizationServerURL + "EntitlementService"; - entitlementServiceStub = new EntitlementServiceStub(configCtx, PDPURL); - CarbonUtils.setBasicAccessSecurityHeaders(username, password, true, entitlementServiceStub._getServiceClient()); - } catch (AxisFault e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error initializing XACML PEP client."); - } - - } - - /** - * Send the XACML authorization request to XAML PDP and return the authorization decision. - * - * @param authzToken - * @param metaData - * @return - */ - public boolean getAuthorizationDecision(AuthzToken authzToken, Map<String, String> metaData) throws AiravataSecurityException { - String decision; - try { - String subject = authzToken.getClaimsMap().get(Constants.USER_NAME); - String action = "/airavata/" + metaData.get(Constants.API_METHOD_NAME); - String decisionString = entitlementServiceStub.getDecisionByAttributes(subject, null, action, null); - //parse the XML decision string and obtain the decision - decision = parseDecisionString(decisionString); - if (Constants.PERMIT.equals(decision)) { - return true; - } else { - logger.error("Authorization decision is: " + decision); - return false; - } - } catch (RemoteException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in authorizing the user."); - } catch (EntitlementServiceException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in authorizing the user."); - } - } - - /** - * This parses the XML based authorization response by the PDP and returns the decision string. - * - * @param decisionString - * @return - * @throws AiravataSecurityException - */ - private String parseDecisionString(String decisionString) throws AiravataSecurityException { - try { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - InputStream inputStream = new ByteArrayInputStream(decisionString.getBytes("UTF-8")); - Document doc = docBuilderFactory.newDocumentBuilder().parse(inputStream); - Node resultNode = doc.getDocumentElement().getFirstChild(); - Node decisionNode = resultNode.getFirstChild(); - String decision = decisionNode.getTextContent(); - return decision; - } catch (ParserConfigurationException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in parsing XACML authorization response."); - } catch (UnsupportedEncodingException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in parsing XACML authorization response."); - } catch (SAXException e) { - logger.error(e.getMessage(), e); - throw new AiravataSecurityException("Error in parsing XACML authorization response."); - } catch (IOException e) { - logger.error("Error in parsing XACML authorization response."); - throw new AiravataSecurityException("Error in parsing XACML authorization response."); - } - } -} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityCheck.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityCheck.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityCheck.java deleted file mode 100644 index dc36211..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityCheck.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * 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 java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -/** - * This is just the definition of the annotation used to mark the API methods to be intercepted. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -@BindingAnnotation -public @interface SecurityCheck { -} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityInterceptor.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityInterceptor.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityInterceptor.java deleted file mode 100644 index 2d35b1b..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityInterceptor.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * 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 org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -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.error.AuthorizationException; -import org.apache.airavata.model.security.AuthzToken; -import org.apache.airavata.security.AiravataSecurityException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; - -/** - * Interceptor of Airavata API calls for the purpose of applying security. - */ -public class SecurityInterceptor implements MethodInterceptor { - private final static Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class); - - @Override - public Object invoke(MethodInvocation invocation) throws Throwable { - //obtain the authz token from the input parameters - AuthzToken authzToken = (AuthzToken) invocation.getArguments()[0]; - //authorize the API call - HashMap<String, String> metaDataMap = new HashMap(); - metaDataMap.put(Constants.API_METHOD_NAME, invocation.getMethod().getName()); - authorize(authzToken, metaDataMap); - //set the user identity info in a thread local to be used in downstream execution. - IdentityContext.set(authzToken); - //let the method call procees upon successful authorization - Object returnObj = invocation.proceed(); - //clean the identity context before the method call returns - IdentityContext.unset(); - return returnObj; - } - - private void authorize(AuthzToken authzToken, Map<String, String> metaData) throws AuthorizationException { - try { - boolean isAPISecured = ServerSettings.isAPISecured(); - if (isAPISecured) { - //check in the cache - - //if not in the cache, perform authorization with the authorization server - AiravataSecurityManager securityManager = SecurityManagerFactory.getSecurityManager(); - boolean isAuthz = securityManager.isUserAuthorized(authzToken, metaData); - if (!isAuthz) { - throw new AuthorizationException("User is not authenticated or authorized."); - } - //put the successful authorization decision in the cache - } - } catch (AiravataSecurityException e) { - logger.error(e.getMessage(), e); - throw new AuthorizationException("Error in authenticating or authorizing user."); - } catch (ApplicationSettingsException e) { - logger.error(e.getMessage(), e); - throw new AuthorizationException("Internal error in authenticating or authorizing user."); - } - } -} - - http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityManagerFactory.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityManagerFactory.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityManagerFactory.java index 0b376a7..dc03b63 100644 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityManagerFactory.java +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityManagerFactory.java @@ -32,15 +32,12 @@ import org.slf4j.LoggerFactory; */ public class SecurityManagerFactory { private final static Logger logger = LoggerFactory.getLogger(SecurityManagerFactory.class); - private static Class secManagerImpl = null; public static AiravataSecurityManager getSecurityManager() throws AiravataSecurityException { try { - if(secManagerImpl == null){ - secManagerImpl = Class.forName(ServerSettings.getSecurityManagerClassName()); - } + Class secManagerImpl = Class.forName(ServerSettings.getSecurityManagerClassName()); AiravataSecurityManager securityManager = (AiravataSecurityManager) secManagerImpl.newInstance(); - return securityManager; + return securityManager; } catch (ClassNotFoundException e) { String error = "Security Manager class could not be found."; logger.error(e.getMessage(), e); http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityModule.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityModule.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityModule.java deleted file mode 100644 index 0b56221..0000000 --- a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/SecurityModule.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * 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.google.inject.matcher.Matchers; -import com.google.inject.AbstractModule; - -/** - * This does the plumbing work of integrating the interceptor with Guice framework for the methods to be - * intercepted upon their invocation. - */ -public class SecurityModule extends AbstractModule { - public void configure(){ - System.out.println("Security module reached..."); - SecurityInterceptor interceptor = new SecurityInterceptor(); - //requestInjection(interceptor); - - bindInterceptor(Matchers.any(), Matchers.annotatedWith(SecurityCheck.class), interceptor); - } - -} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCache.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCache.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCache.java new file mode 100644 index 0000000..a563caa --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCache.java @@ -0,0 +1,61 @@ +/* + * + * 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.authzcache; + +import javax.management.MXBean; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.airavata.common.exception.ApplicationSettingsException; +import org.apache.airavata.common.utils.ServerSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AuthzCache extends LinkedHashMap<AuthzCacheIndex, AuthzCacheEntry> { + + private static int MAX_SIZE; + private final static Logger logger = LoggerFactory.getLogger(AuthzCache.class); + + private static AuthzCache authzCache = null; + + public static AuthzCache getInstance() throws ApplicationSettingsException { + if (authzCache == null) { + synchronized (AuthzCache.class) { + if (authzCache == null) { + authzCache = new AuthzCache(ServerSettings.getCacheSize()); + } + } + } + return authzCache; + } + + private AuthzCache(int initialCapacity) { + super(initialCapacity); + MAX_SIZE = initialCapacity; + } + + @Override + protected boolean removeEldestEntry(Map.Entry<AuthzCacheIndex, AuthzCacheEntry> eldest) { + //TODO: following info log is for demonstration purposes. Remove it. + logger.info("Authz cache max size exceeded. Removing the old entries."); + return size() > MAX_SIZE; + } +} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCachedStatus.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCachedStatus.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCachedStatus.java new file mode 100644 index 0000000..e166265 --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/authzcache/AuthzCachedStatus.java @@ -0,0 +1,34 @@ +/* + * + * 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.authzcache; + +/** + * This enum defines the status of the authorization cache returned by the authorization cache manager + * when an authorization status is checked against an authorization request. + */ +public enum AuthzCachedStatus { + /*Authorization decision is cached for the given authrization request and the decision authorizes the request.*/ + AUTHORIZED, + /*Authorization decision is cached for the given authorization request and the decision denies authorization.*/ + NOT_AUTHORIZED, + /*Authorization decision is not either cached or the cached entry is invalid such that re-authorization is needed.*/ + NOT_CACHED +} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityCheck.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityCheck.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityCheck.java new file mode 100644 index 0000000..d4b4952 --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityCheck.java @@ -0,0 +1,36 @@ +/* + * + * 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.interceptor; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import com.google.inject.BindingAnnotation; + +/** + * This is just the definition of the annotation used to mark the API methods to be intercepted. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@BindingAnnotation +public @interface SecurityCheck { +} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityInterceptor.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityInterceptor.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityInterceptor.java new file mode 100644 index 0000000..1b4f0ad --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityInterceptor.java @@ -0,0 +1,83 @@ +/* + * + * 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.interceptor; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.airavata.api.server.security.AiravataSecurityManager; +import org.apache.airavata.api.server.security.IdentityContext; +import org.apache.airavata.api.server.security.SecurityManagerFactory; +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.error.AuthorizationException; +import org.apache.airavata.model.security.AuthzToken; +import org.apache.airavata.security.AiravataSecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Interceptor of Airavata API calls for the purpose of applying security. + */ +public class SecurityInterceptor implements MethodInterceptor { + private final static Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class); + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + //obtain the authz token from the input parameters + AuthzToken authzToken = (AuthzToken) invocation.getArguments()[0]; + //authorize the API call + HashMap<String, String> metaDataMap = new HashMap(); + metaDataMap.put(Constants.API_METHOD_NAME, invocation.getMethod().getName()); + authorize(authzToken, metaDataMap); + //set the user identity info in a thread local to be used in downstream execution. + IdentityContext.set(authzToken); + //let the method call procees upon successful authorization + Object returnObj = invocation.proceed(); + //clean the identity context before the method call returns + IdentityContext.unset(); + return returnObj; + } + + private void authorize(AuthzToken authzToken, Map<String, String> metaData) throws AuthorizationException { + try { + boolean isAPISecured = ServerSettings.isAPISecured(); + if (isAPISecured) { + AiravataSecurityManager securityManager = SecurityManagerFactory.getSecurityManager(); + boolean isAuthz = securityManager.isUserAuthorized(authzToken, metaData); + if (!isAuthz) { + throw new AuthorizationException("User is not authenticated or authorized."); + } + } + } catch (AiravataSecurityException e) { + logger.error(e.getMessage(), e); + throw new AuthorizationException("Error in authenticating or authorizing user."); + } catch (ApplicationSettingsException e) { + logger.error(e.getMessage(), e); + throw new AuthorizationException("Internal error in authenticating or authorizing user."); + } + } +} + + http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityModule.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityModule.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityModule.java new file mode 100644 index 0000000..f30dc9b --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/interceptor/SecurityModule.java @@ -0,0 +1,41 @@ +/* + * + * 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.interceptor; + +import com.google.inject.matcher.Matchers; +import com.google.inject.AbstractModule; +import org.apache.airavata.api.server.security.interceptor.SecurityCheck; +import org.apache.airavata.api.server.security.interceptor.SecurityInterceptor; + +/** + * This does the plumbing work of integrating the interceptor with Guice framework for the methods to be + * intercepted upon their invocation. + */ +public class SecurityModule extends AbstractModule { + public void configure(){ + System.out.println("Security module reached..."); + SecurityInterceptor interceptor = new SecurityInterceptor(); + //requestInjection(interceptor); + + bindInterceptor(Matchers.any(), Matchers.annotatedWith(SecurityCheck.class), interceptor); + } + +} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/oauth/DefaultOAuthClient.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/oauth/DefaultOAuthClient.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/oauth/DefaultOAuthClient.java new file mode 100644 index 0000000..74b36cf --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/oauth/DefaultOAuthClient.java @@ -0,0 +1,94 @@ +/* + * + * 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.oauth; + +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.oauth2.stub.OAuth2TokenValidationServiceStub; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken; +import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.utils.CarbonUtils; + +import java.rmi.RemoteException; + +/** + * This is the default OAuth Client that talks to WSO2 IS's OAuth Authentication Server + * to get the OAuth token validated. + */ +public class DefaultOAuthClient { + + private OAuth2TokenValidationServiceStub stub; + private final static Logger logger = LoggerFactory.getLogger(DefaultOAuthClient.class); + public static final String BEARER_TOKEN_TYPE = "bearer"; + + /** + * OAuth2TokenValidationService Admin Service Client + * + * @param auhorizationServerURL + * @param username + * @param password + * @param configCtx + * @throws Exception + */ + public DefaultOAuthClient(String auhorizationServerURL, String username, String password, + ConfigurationContext configCtx) throws AiravataSecurityException { + try { + String serviceURL = auhorizationServerURL + "OAuth2TokenValidationService"; + stub = new OAuth2TokenValidationServiceStub(configCtx, serviceURL); + CarbonUtils.setBasicAccessSecurityHeaders(username, password, true, stub._getServiceClient()); + } catch (AxisFault e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error initializing OAuth client."); + } + } + + /** + * Validates the OAuth 2.0 access token + * + * @param accessToken + * @return + * @throws Exception + */ + public OAuth2TokenValidationResponseDTO validateAccessToken(String accessToken) + throws AiravataSecurityException { + + try { + OAuth2TokenValidationRequestDTO oauthReq = new OAuth2TokenValidationRequestDTO(); + OAuth2TokenValidationRequestDTO_OAuth2AccessToken token = + new OAuth2TokenValidationRequestDTO_OAuth2AccessToken(); + token.setIdentifier(accessToken); + token.setTokenType(BEARER_TOKEN_TYPE); + oauthReq.setAccessToken(token); + return stub.validate(oauthReq); + } catch (RemoteException e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error in validating the OAuth access token."); + } /*catch (ApplicationSettingsException e) { + logger.error(e.getMessage(), e); + throw new AiravataSecurityException("Error in reading OAuth configuration."); + }*/ + } + +} http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/xacml/DefaultPAPClient.java ---------------------------------------------------------------------- diff --git a/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/xacml/DefaultPAPClient.java b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/xacml/DefaultPAPClient.java new file mode 100644 index 0000000..110d4d3 --- /dev/null +++ b/airavata-api/airavata-api-server/src/main/java/org/apache/airavata/api/server/security/xacml/DefaultPAPClient.java @@ -0,0 +1,125 @@ +/* + * + * 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.xacml; + +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/27774766/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 af8ca96..dba0525 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 @@ -42,6 +42,7 @@ public final class Constants { public static final String KEYSTORE_PATH = "keystore.path"; public static final String KEYSTORE_PASSWORD = "keystore.password"; public static final String TLS_CLIENT_TIMEOUT = "TLS.client.timeout"; + public static final String API_METHOD_NAME = "api.method.name"; //constants in XACML authorization response. @@ -52,6 +53,12 @@ public final class Constants { public static final String AUTHORIZATION_POLICY_NAME = "authorization.policy"; + public static final String AUTHZ_CACHE_MANAGER_CLASS = "authz.cache.manager.class"; + + public static final String AUTHZ_CACHE_ENABLED = "authz.cache.enabled"; + + public static final String IN_MEMORY_CACHE_SIZE = "in.memory.cache.size"; + //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/27774766/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 d87da70..b47a939 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 @@ -30,25 +30,25 @@ import org.slf4j.LoggerFactory; public class ServerSettings extends ApplicationSettings { - private static final Logger log = LoggerFactory.getLogger(ServerSettings.class); + private static final Logger log = LoggerFactory.getLogger(ServerSettings.class); private static final String DEFAULT_USER = "default.registry.user"; private static final String DEFAULT_USER_PASSWORD = "default.registry.password"; - private static final String DEFAULT_USER_GATEWAY = "default.registry.gateway"; - private static final String OUTPUT_LOCATION = "out.location"; + private static final String DEFAULT_USER_GATEWAY = "default.registry.gateway"; + private static final String OUTPUT_LOCATION = "out.location"; private static final String SERVER_CONTEXT_ROOT = "server.context-root"; public static final String IP = "ip"; // Orchestrator Constants public static final String ORCHESTRATOR_SERVER_HOST = "orchestrator.server.host"; public static final String ORCHESTRATOR_SERVER_PORT = "orchestrator.server.port"; - public static final String ORCHESTRATOR_SERVER_NAME = "orchestrator.server.name"; - // Gfac constants + public static final String ORCHESTRATOR_SERVER_NAME = "orchestrator.server.name"; + // Gfac constants public static final String GFAC_SERVER_HOST = "gfac.server.host"; public static final String GFAC_SERVER_PORT = "gfac.server.port"; public static final String GFAC_SERVER_NAME = "gfac.server.name"; public static final String GFAC_THREAD_POOL_SIZE = "gfac.thread.pool.size"; - public static final int DEFAULT_GFAC_THREAD_POOL_SIZE = 50; + public static final int DEFAULT_GFAC_THREAD_POOL_SIZE = 50; public static final String GFAC_CONFIG_XML = "gfac-config.xml"; // Credential Store constants public static final String CREDENTIAL_SERVER_HOST = "credential.store.server.host"; @@ -99,9 +99,9 @@ public class ServerSettings extends ApplicationSettings { private static boolean stopAllThreads = false; private static boolean emailBaseNotificationEnable; - private static String outputLocation; + private static String outputLocation; - public static String getDefaultUser() throws ApplicationSettingsException { + public static String getDefaultUser() throws ApplicationSettingsException { return getSetting(DEFAULT_USER); } @@ -281,7 +281,7 @@ public class ServerSettings extends ApplicationSettings { return getSetting(Constants.ADMIN_PASSWORD); } - public static String getAuthorizationPoliyName() throws ApplicationSettingsException{ + public static String getAuthorizationPoliyName() throws ApplicationSettingsException { return getSetting(Constants.AUTHORIZATION_POLICY_NAME); } @@ -289,9 +289,9 @@ public class ServerSettings extends ApplicationSettings { return getSetting(ZOOKEEPER_SERVER_CONNECTION, "localhost:2181"); } - public static int getZookeeperTimeout() { - return Integer.valueOf(getSetting(ZOOKEEPER_TIMEOUT, "3000")); - } + public static int getZookeeperTimeout() { + return Integer.valueOf(getSetting(ZOOKEEPER_TIMEOUT, "3000")); + } public static String getGFacServerName() throws ApplicationSettingsException { return getSetting(GFAC_SERVER_NAME); @@ -308,43 +308,47 @@ public class ServerSettings extends ApplicationSettings { public static int getGFacThreadPoolSize() { try { String threadPoolSize = getSetting(GFAC_THREAD_POOL_SIZE); - if (threadPoolSize != null && !threadPoolSize.isEmpty()) { - return Integer.valueOf(threadPoolSize); - } else { - log.warn("Thread pool size is not configured, use default gfac thread pool size " + - DEFAULT_GFAC_THREAD_POOL_SIZE); - } + if (threadPoolSize != null && !threadPoolSize.isEmpty()) { + return Integer.valueOf(threadPoolSize); + } else { + log.warn("Thread pool size is not configured, use default gfac thread pool size " + + DEFAULT_GFAC_THREAD_POOL_SIZE); + } } catch (ApplicationSettingsException e) { - log.warn("Couldn't read thread pool size from configuration on exception, use default gfac thread pool " + - "size " + DEFAULT_GFAC_THREAD_POOL_SIZE); + log.warn("Couldn't read thread pool size from configuration on exception, use default gfac thread pool " + + "size " + DEFAULT_GFAC_THREAD_POOL_SIZE); } - return DEFAULT_GFAC_THREAD_POOL_SIZE; + return DEFAULT_GFAC_THREAD_POOL_SIZE; } - public static String getOrchestratorServerName() throws ApplicationSettingsException { - return getSetting(ORCHESTRATOR_SERVER_NAME); - } + public static String getOrchestratorServerName() throws ApplicationSettingsException { + return getSetting(ORCHESTRATOR_SERVER_NAME); + } - public static String getOrchestratorServerHost() throws ApplicationSettingsException { - return getSetting(ORCHESTRATOR_SERVER_HOST); - } + public static String getOrchestratorServerHost() throws ApplicationSettingsException { + return getSetting(ORCHESTRATOR_SERVER_HOST); + } - public static int getOrchestratorServerPort() throws ApplicationSettingsException { - return Integer.valueOf(getSetting(ORCHESTRATOR_SERVER_PORT)); - } + public static int getOrchestratorServerPort() throws ApplicationSettingsException { + return Integer.valueOf(getSetting(ORCHESTRATOR_SERVER_PORT)); + } public static boolean isTLSEnabled() throws ApplicationSettingsException { return Boolean.valueOf(getSetting(Constants.IS_TLS_ENABLED)); } + public static int getTLSServerPort() throws ApplicationSettingsException { return Integer.valueOf(getSetting(Constants.TLS_SERVER_PORT)); } + public static String getKeyStorePath() throws ApplicationSettingsException { return getSetting(Constants.KEYSTORE_PATH); } + public static String getKeyStorePassword() throws ApplicationSettingsException { return getSetting(Constants.KEYSTORE_PASSWORD); } + public static int getTLSClientTimeout() throws ApplicationSettingsException { return Integer.valueOf(getSetting(Constants.TLS_CLIENT_TIMEOUT)); } @@ -353,7 +357,19 @@ public class ServerSettings extends ApplicationSettings { return getSetting(Constants.SECURITY_MANAGER_CLASS); } - public static String getOutputLocation() { - return getSetting(OUTPUT_LOCATION, System.getProperty("java.io.tmpdir")); - } + public static String getAuthzCacheManagerClassName() throws ApplicationSettingsException { + return getSetting(Constants.AUTHZ_CACHE_MANAGER_CLASS); + } + + public static boolean isAuthzCacheEnabled() throws ApplicationSettingsException { + return Boolean.valueOf(getSetting(Constants.AUTHZ_CACHE_ENABLED)); + } + + public static int getCacheSize() throws ApplicationSettingsException { + return Integer.valueOf(getSetting(Constants.IN_MEMORY_CACHE_SIZE)); + } + + public static String getOutputLocation() { + return getSetting(OUTPUT_LOCATION, System.getProperty("java.io.tmpdir")); + } } http://git-wip-us.apache.org/repos/asf/airavata/blob/27774766/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 58a42a3..fb57382 100644 --- a/modules/configuration/server/src/main/resources/airavata-server.properties +++ b/modules/configuration/server/src/main/resources/airavata-server.properties @@ -229,14 +229,24 @@ zookeeper.timeout=30000 ######################################################################## api.secured=true security.manager.class=org.apache.airavata.api.server.security.DefaultAiravataSecurityManager +### TLS related configuration #### TLS.enabled=true TLS.api.server.port=9930 TLS.client.timeout=10000 +#### keystore configuration #### keystore.path=airavata.jks keystore.password=airavata +#### trust store configuration #### trust.store=client_truststore.jks trust.store.password=airavata +#### remote authorization server url #### remote.oauth.authorization.server=https://localhost:9443/services/ +#### xacml based authorization policy #### authorization.policy=airavata-default-xacml-policy +#### authorization cache related configuration #### +authz.cache.enabled=true +authz.cache.manager.class=org.apache.airavata.api.server.security.cache.DefaultAuthzCacheManager +in.memory.cache.size=1000 +#### admin user credentials of authorization server #### admin.user.name=admin admin.password=admin \ No newline at end of file
