/* * 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.geode.internal.security; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.Principal; import java.util.Set; import org.apache.geode.cache.Cache; import org.apache.geode.cache.operations.*; import org.apache.geode.cache.operations.internal.GetOperationContextImpl; import org.apache.geode.i18n.LogWriterI18n; import org.apache.geode.internal.ClassLoadUtil; import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.security.AccessControl; import org.apache.geode.security.NotAuthorizedException; /** * This class implements post-processing authorization calls for various operations. It provides * methods to invoke authorization callback ({@link AccessControl#authorizeOperation}) to invoke the * post-processing callback that may modify the results. The data being passed for the operation is * encapsulated in a {@link OperationContext} object that can be modified by the post-processing * authorization callbacks. * * @since GemFire 5.5 */ public class AuthorizeRequestPP { private AccessControl postAuthzCallback; private final ClientProxyMembershipID id; private final LogWriterI18n logger; private final Principal principal; private final boolean isPrincipalSerializable; public AuthorizeRequestPP(String postAuthzFactoryName, ClientProxyMembershipID id, Principal principal, Cache cache) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { this.id = id; this.principal = principal; if (this.principal instanceof Serializable) { this.isPrincipalSerializable = true; } else { this.isPrincipalSerializable = false; } this.logger = cache.getSecurityLoggerI18n(); Method postAuthzMethod = ClassLoadUtil.methodFromName(postAuthzFactoryName); this.postAuthzCallback = (AccessControl) postAuthzMethod.invoke(null, (Object[]) null); this.postAuthzCallback.init(principal, id.getDistributedMember(), cache); if (this.logger.infoEnabled()) { this.logger.info( LocalizedStrings.AuthorizeRequestPP_AUTHORIZEREQUESTPP_SETTING_POST_PROCESS_AUTHORIZATION_CALLBACK_TO_1_FOR_CLIENT_0, new Object[] {id, postAuthzFactoryName}); } } public AccessControl getPostAuthzCallback() { return this.postAuthzCallback; } public GetOperationContext getAuthorize(String regionName, Object key, Object result, boolean isObject, GetOperationContext getContext) throws NotAuthorizedException { if (getContext == null) { getContext = new GetOperationContextImpl(key, true); } else { getContext.setPostOperation(); } getContext.setObject(result, isObject); if (!this.postAuthzCallback.authorizeOperation(regionName, getContext)) { String errStr = LocalizedStrings.AuthorizeRequestPP_IN_POSTPROCESS_NOT_AUTHORIZED_TO_PERFORM_GET_OPERATION_ON_REGION_0 .toLocalizedString(regionName); this.logger.warning(LocalizedStrings.TWO_ARG_COLON, new Object[] {this.id, errStr}); if (this.isPrincipalSerializable) { throw new NotAuthorizedException(errStr, this.principal); } else { throw new NotAuthorizedException(errStr); } } else { if (this.logger.finestEnabled()) { this.logger .finest(this.id + ": In post-process: authorized to perform GET operation on region [" + regionName + ']'); } } return getContext; } public QueryOperationContext queryAuthorize(String queryString, Set regionNames, Object queryResult, QueryOperationContext queryContext, Object[] queryParams) throws NotAuthorizedException { if (queryContext == null) { queryContext = new QueryOperationContext(queryString, regionNames, true, queryParams); } else { queryContext.setPostOperation(); } queryContext.setQueryResult(queryResult); if (!this.postAuthzCallback.authorizeOperation(null, queryContext)) { String errStr = LocalizedStrings.AuthorizeRequestPP_IN_POSTPROCESS_NOT_AUTHORIZED_TO_PERFORM_QUERY_OPERATION_0_ON_THE_CACHE .toLocalizedString(queryString); this.logger.warning(LocalizedStrings.TWO_ARG_COLON, new Object[] {this.id, errStr}); if (this.isPrincipalSerializable) { throw new NotAuthorizedException(errStr, this.principal); } else { throw new NotAuthorizedException(errStr); } } else { if (this.logger.finestEnabled()) { this.logger.finest(this.id + ": In post-process: authorized to perform QUERY operation [" + queryString + "] on cache"); } } return queryContext; } public QueryOperationContext executeCQAuthorize(String cqName, String queryString, Set regionNames, Object queryResult, QueryOperationContext executeCQContext) throws NotAuthorizedException { if (executeCQContext == null) { executeCQContext = new ExecuteCQOperationContext(cqName, queryString, regionNames, true); } else { executeCQContext.setPostOperation(); } executeCQContext.setQueryResult(queryResult); if (!this.postAuthzCallback.authorizeOperation(null, executeCQContext)) { String errStr = LocalizedStrings.AuthorizeRequestPP_IN_POSTPROCESS_NOT_AUTHORIZED_TO_PERFORM_EXECUTE_CQ_OPERATION_0_ON_THE_CACHE .toLocalizedString(queryString); this.logger.warning(LocalizedStrings.TWO_ARG_COLON, new Object[] {this.id, errStr}); if (this.isPrincipalSerializable) { throw new NotAuthorizedException(errStr, this.principal); } else { throw new NotAuthorizedException(errStr); } } else { if (this.logger.finestEnabled()) { this.logger .finest(this.id + ": In post-process: authorized to perform EXECUTE_CQ operation [" + queryString + "] on cache"); } } return executeCQContext; } public KeySetOperationContext keySetAuthorize(String regionName, Set keySet, KeySetOperationContext keySetContext) throws NotAuthorizedException { if (keySetContext == null) { keySetContext = new KeySetOperationContext(true); } else { keySetContext.setPostOperation(); } keySetContext.setKeySet(keySet); if (!this.postAuthzCallback.authorizeOperation(regionName, keySetContext)) { String errStr = LocalizedStrings.AuthorizeRequestPP_IN_POSTPROCESS_NOT_AUTHORIZED_TO_PERFORM_KEY_SET_OPERATION_ON_REGION_0 .toLocalizedString(regionName); this.logger.warning(LocalizedStrings.TWO_ARG_COLON, new Object[] {this.id, errStr}); if (this.isPrincipalSerializable) { throw new NotAuthorizedException(errStr, this.principal); } else { throw new NotAuthorizedException(errStr); } } else { if (this.logger.finestEnabled()) { this.logger.finest( this.id + ": In post-process: authorized to perform KEY_SET operation on region [" + regionName + ']'); } } return keySetContext; } public ExecuteFunctionOperationContext executeFunctionAuthorize(Object oneResult, ExecuteFunctionOperationContext executeContext) throws NotAuthorizedException { executeContext.setResult(oneResult); final String regionName = executeContext.getRegionName(); if (!this.postAuthzCallback.authorizeOperation(regionName, executeContext)) { String errStr = LocalizedStrings.AuthorizeRequestPP_0_NOT_AUTHORIZED_TO_PERFORM_EXECUTE_REGION_FUNCTION_1 .toLocalizedString(new Object[] {toString(), regionName}); if (this.logger.warningEnabled()) { this.logger.warning(LocalizedStrings.ONE_ARG, errStr); } if (this.isPrincipalSerializable) { throw new NotAuthorizedException(errStr, this.principal); } else { throw new NotAuthorizedException(errStr); } } else { if (this.logger.finestEnabled()) { this.logger.finest(this.id + ": In post-process: authorized to perform EXECUTE_REGION_FUNCTION operation on region [" + regionName + ']'); } } return executeContext; } public void close() { this.postAuthzCallback.close(); } }