Package org.glassfish.security.services.impl.authorization

Source Code of org.glassfish.security.services.impl.authorization.AuthorizationServiceImpl

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.security.services.impl.authorization;

import java.net.URI;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.security.AccessController;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.security.Policy;
import java.security.CodeSource;
import java.security.CodeSigner;
import javax.security.auth.Subject;

import org.glassfish.security.services.api.authorization.AuthorizationService;
import org.glassfish.security.services.api.authorization.AzAction;
import org.glassfish.security.services.api.authorization.AzResource;
import org.glassfish.security.services.api.authorization.AzResult;
import org.glassfish.security.services.api.authorization.AzSubject;
import org.glassfish.security.services.api.context.SecurityContextService;
import org.glassfish.security.services.common.PrivilegedLookup;
import org.glassfish.security.services.common.Secure;
import org.glassfish.security.services.config.SecurityConfiguration;
import org.glassfish.security.services.impl.ServiceFactory;
import org.glassfish.security.services.impl.ServiceLogging;

import javax.inject.Inject;
import javax.inject.Singleton;
import org.jvnet.hk2.annotations.Service;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.ServiceLocator;

import com.sun.enterprise.config.serverbeans.Domain;

import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.enterprise.util.LocalStringManagerImpl;
import org.glassfish.logging.annotation.LogMessageInfo;

import org.glassfish.security.services.api.authorization.*;
import org.glassfish.security.services.api.common.Attributes;
import org.glassfish.security.services.config.SecurityProvider;
import org.glassfish.security.services.spi.authorization.AuthorizationProvider;

/**
* <code>AuthorizationServiceImpl</code> implements
* <code>{@link org.glassfish.security.services.api.authorization.AuthorizationService}</code>
* by delegating authorization decisions to configured
* <code>{@link org.glassfish.security.services.spi.AuthorizationProvider}</code>
* instances.
*/
@Service
@Singleton
@Secure(accessPermissionName = "security/service/authorization")
public final class AuthorizationServiceImpl implements AuthorizationService, PostConstruct {
    private static final Level DEBUG_LEVEL = Level.FINER;
    private static final Logger logger =
        Logger.getLogger(ServiceLogging.SEC_SVCS_LOGGER,ServiceLogging.SHARED_LOGMESSAGE_RESOURCE);
    private static LocalStringManagerImpl localStrings =
        new LocalStringManagerImpl(AuthorizationServiceImpl.class);
    @Inject
    private volatile Domain domain;

    @Inject
    private volatile ServiceLocator serviceLocator;
   
    private volatile org.glassfish.security.services.config.AuthorizationService atzSvCfg;

    @Inject
    private volatile SecurityContextService securityContextService;

    private volatile SecurityProvider atzPrvConfig;
   
    private volatile AuthorizationProvider provider;
   
    private static final CodeSource NULL_CODESOURCE = new CodeSource(null, (CodeSigner[])null);

    enum InitializationState {
        NOT_INITIALIZED,
        SUCCESS_INIT,
        FAILED_INIT
    }
    private volatile InitializationState initialized = InitializationState.NOT_INITIALIZED;
    private volatile String reasonInitFailed =
        localStrings.getLocalString("service.atz.never_init","Authorization Service never initialized.");

    private final List<AzAttributeResolver> attributeResolvers =
            Collections.synchronizedList(new java.util.ArrayList<AzAttributeResolver>());

  private boolean isDebug() {
    return logger.isLoggable(DEBUG_LEVEL);
  }

    /**
     * Initialize the security service instance with the specific security service configuration.
     *
     * @see org.glassfish.security.services.api.SecurityService#initialize
     */
    @Override
    public void initialize(final SecurityConfiguration securityServiceConfiguration) {

        if ( InitializationState.NOT_INITIALIZED != initialized ) {
            return;
        }

        try {
            // Get service level config
            if ( !( securityServiceConfiguration instanceof org.glassfish.security.services.config.AuthorizationService ) ) {
                throw new IllegalStateException(
                    localStrings.getLocalString("service.atz.not_config","The Authorization service is not configured in the domain configuration file."));
            }
            atzSvCfg = (org.glassfish.security.services.config.AuthorizationService) securityServiceConfiguration;

            // Get provider level config, consider only one provider for now and take the first provider found.
            List<SecurityProvider> providersConfig = atzSvCfg.getSecurityProviders();
            if ( (providersConfig == null) || ( (atzPrvConfig = providersConfig.get(0)) == null ) ) {
                throw new IllegalStateException(
                    localStrings.getLocalString("service.atz.no_prov_config","No provider configured for the Authorization service in the domain configuration file."));
            }

            // Get the provider
            final String providerName = atzPrvConfig.getName();
            if ( isDebug() ) {
                logger.log(DEBUG_LEVEL, "Attempting to get Authorization provider \"{0}\".", providerName );
            }
            provider =  AccessController.doPrivileged(
                            new PrivilegedLookup<AuthorizationProvider>(
                                    serviceLocator, AuthorizationProvider.class, providerName));
            if (provider == null) {
                throw new IllegalStateException(
                    localStrings.getLocalString("service.atz.not_provider","Authorization Provider {0} not found.", providerName));
            }

            // Initialize the provider
            provider.initialize(atzPrvConfig);

            initialized = InitializationState.SUCCESS_INIT;
            reasonInitFailed = null;

            logger.log(Level.INFO, ATZSVC_INITIALIZED);

        } catch ( Exception e ) {
            String eMsg = e.getMessage();
            String eClass = e.getClass().getName();
            reasonInitFailed = localStrings.getLocalString("service.atz.init_failed",
                "Authorization Service initialization failed, exception {0}, message {1}", eClass, eMsg);
            logger.log(Level.WARNING, ATZSVC_INIT_FAILED, new Object[] {eClass, eMsg});
            throw new RuntimeException( reasonInitFailed, e );
        } finally {
            if ( InitializationState.SUCCESS_INIT != initialized ) {
                initialized = InitializationState.FAILED_INIT;
            }
        }
    }

    /**
     * Determine whether the given Subject has been granted the specified Permission
     * by delegating to the configured java.security.Policy object.  This method is
     * a high-level convenience method that tests for a Subject-based permission
     * grant without reference to the AccessControlContext of the caller.
     *
     * In addition, this method isolates the query from the underlying Policy configuration
     * model.  It could, for example, multiplex queries across multiple instances of Policy
     * configured in an implementation-specific way such that different threads, or different
     * applications, query different Policy objects.  The initial implementation simply
     * delegates to the configured Policy as defined by Java SE.
     *
     * @param subject The Subject for which permission is being tested.
     * @param permission The Permission being queried.
     * @return True or false, depending on whether the specified Permission
     * is granted to the Subject by the configured Policy.
     * @throws IllegalArgumentException Given null or illegal subject or permission
     * @see AuthorizationService#isPermissionGranted(javax.security.auth.Subject, java.security.Permission)
     */
    @Override
  public boolean isPermissionGranted(
        final Subject subject, final Permission permission) {

        // Validate inputs
        if ( null == subject ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.subject_null", "The supplied Subject is null."));
        }
        if ( null == permission ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.permission_null","The supplied Permission is null."));
        }

        Set<Principal> principalset = subject.getPrincipals();
        Principal[] principalAr = (principalset.size() == 0) ? null : principalset.toArray(new Principal[principalset.size()]);
        ProtectionDomain pd = new ProtectionDomain(NULL_CODESOURCE, null, null, principalAr);
        Policy policy = Policy.getPolicy();
        boolean result = policy.implies(pd, permission);

        return result;
  }


    /**
     * Determine whether the given Subject is authorized to access the given resource,
     * specified by a URI.
     *
     * @param subject The Subject being tested.
     * @param resource URI of the resource being tested.
     * @return True or false, depending on whether the access is authorized.
     * @throws IllegalArgumentException Given null or illegal subject or resource
     * @throws IllegalStateException Service was not initialized.
     * @see AuthorizationService#isAuthorized(javax.security.auth.Subject, java.net.URI)
     */
    @Override
  public boolean isAuthorized(Subject subject, URI resource) {
    return isAuthorized(subject, resource, null);
  }


    /**
     * Determine whether the given Subject is authorized to access the given resource,
     * specified by a URI.
     *
     * @param subject The Subject being tested.
     * @param resource URI of the resource being tested.
     * @param action The action, with respect to the resource parameter,
     * for which authorization is desired. To check authorization for all actions,
     * action is represented by null or "*".
     * @return True or false, depending on whether the access is authorized.
     * @throws IllegalArgumentException Given null or illegal subject or resource
     * @throws IllegalStateException Service was not initialized.
     * @see AuthorizationService#isAuthorized(javax.security.auth.Subject, java.net.URI, String)
     */
    @Override
    public boolean isAuthorized(final Subject subject, final URI resource, final String action) {

        checkServiceAvailability();

        // Validate inputs
        if ( null == subject ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.subject_null", "The supplied Subject is null."));
        }
        if ( null == resource ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.resource_null", "The supplied Resource is null."));
        }
        // Note: null action means all actions (i.e., no action condition)

        // Convert parameters
        AzSubject azSubject = makeAzSubject( subject );
        AzResource azResource = makeAzResource( resource );
        AzAction azAction = makeAzAction(action);

        AzResult azResult = getAuthorizationDecision(azSubject, azResource, azAction);

        boolean result =
            AzResult.Status.OK.equals(azResult.getStatus()) &&
            AzResult.Decision.PERMIT.equals(azResult.getDecision());
        return result;
  }


    /**
     * The primary authorization method.  The isAuthorized() methods call this method
     * after converting their arguments into the appropriate attribute collection type.
     * It returns a full AzResult, including authorization status, decision, and
     * obligations.
     *
     * This method performs two steps prior to invoking the configured AuthorizationProvider
     * to evaluate the request:  First, it acquires the current AzEnvironment attributes by
     * calling the Security Context service.  Second, it calls the Role Mapping service to
     * determine which roles the subject has, and adds the resulting role attributes into
     * the AzSubject.
     *
     * @param subject The attributes collection representing the Subject for which an authorization
     * decision is requested.
     * @param resource The attributes collection representing the resource for which access is
     * being requested.
     * @param action  The attributes collection representing the action, with respect to the resource,
     * for which access is being requested.  A null action is interpreted as all
     * actions, however all actions may also be represented by the AzAction instance.
     * See <code>{@link org.glassfish.security.services.api.authorization.AzAction}</code>.
     * @return The AzResult indicating the result of the access decision.
     * @throws IllegalArgumentException Given null or illegal subject or resource
     * @throws IllegalStateException Service was not initialized.
     * @see AuthorizationService#getAuthorizationDecision
     */
    @Override
    public AzResult getAuthorizationDecision(
            final AzSubject subject,
            final AzResource resource,
            final AzAction action) {

        checkServiceAvailability();

        // Validate inputs
        if ( null == subject ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.subject_null", "The supplied Subject is null."));
        }
        if ( null == resource ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.resource_null", "The supplied Resource is null."));
        }

        // TODO: setup current AzEnvironment instance. Should a null or empty instance to represent current environment?
        final AzEnvironment env = new AzEnvironmentImpl();
        final Attributes attrs = securityContextService.getEnvironmentAttributes();
        for (String attrName : attrs.getAttributeNames()) {
            env.addAttribute(attrName, attrs.getAttributeValue(attrName), true);
        }

        AzResult result =  provider.getAuthorizationDecision(
            subject, resource, action, env, attributeResolvers );

        if ( isDebug() ) {
            logger.log(DEBUG_LEVEL,
            "Authorization Service result for {0} was {1}.",
            new String[]{ subject.toString(), result.toString() } );
        }

        return result;
  }


    /**
     * Convert a Java Subject into a typed attributes collection.
     *
     * @param subject The Subject to convert.
     * @return The resulting AzSubject.
     * @throws IllegalArgumentException Given null or illegal subject
     * @see AuthorizationService#makeAzSubject(javax.security.auth.Subject)
     */
    @Override
    public AzSubject makeAzSubject(final Subject subject) {
        AzSubject azs = new AzSubjectImpl(subject);
        return azs;
    }


    /**
     * Convert a resource, expressed as a URI, into a typed attributes collection.
     * <p>
     * Query parameters in the given URI are appended to this
     * <code>AzResource</code> instance attributes collection.
     *
     * @param resource The URI to convert.
     * @return The resulting AzResource.
     * @see AuthorizationService#makeAzResource(java.net.URI)
     * @throws IllegalArgumentException Given null or illegal resource
     */
    @Override
    public AzResource makeAzResource(final URI resource) {
        AzResource azr = new AzResourceImpl( resource );
        return azr;
    }


    /**
     * Convert an action, expressed as a String, into a typed attributes collection.
     *
     * @param action The action to convert. null or "*" represents all actions.
     * @return The resulting AzAction.
     * @see AuthorizationService#makeAzAction(String)
     */
    @Override
    public AzAction makeAzAction(final String action) {
        AzAction aza = new AzActionImpl( action );
        return aza;
    }


    /**
     * Find an existing PolicyDeploymentContext, or create a new one if one does not
     * already exist for the specified appContext.  The context will be returned in
     * an "open" state, and will stay that way until commit() or delete() is called.
     *
     * @param appContext The application context for which the PolicyDeploymentContext
     * is desired.
     * @return The resulting PolicyDeploymentContext,
     * null if the configured providers do not support this feature.
     * @throws IllegalStateException Service was not initialized.
     * @see AuthorizationService#findOrCreateDeploymentContext(String)
     */
    @Override
    public PolicyDeploymentContext findOrCreateDeploymentContext(
            final String appContext) {

        checkServiceAvailability();

        // TODO: Unsupported Operation Exception undocumented, not optional

        return provider.findOrCreateDeploymentContext(appContext);
  }


    /**
     * Called when the instance has been created and the component is
     * about to be place into commission.
     * <p>
     * The component has been injected with any dependency and
     * will be placed into commission by the subsystem.
     * <p>
     * Hk2 will catch all unchecked exceptions,
     * and will consequently cause the backing inhabitant to be released.
     *
     * @see org.glassfish.hk2.api.PostConstruct#postConstruct()
     */
    @Override
    public void postConstruct() {

        org.glassfish.security.services.config.AuthorizationService atzConfiguration =
                ServiceFactory.getSecurityServiceConfiguration(
                        domain, org.glassfish.security.services.config.AuthorizationService.class);

        initialize(atzConfiguration);
    }


    /**
     * Appends the given <code>{@link org.glassfish.security.services.api.authorization.AzAttributeResolver}</code>
     * instance to the internal ordered list of <code>AzAttributeResolver</code> instances,
     * if not currently in the list based on
     * <code>{@link org.glassfish.security.services.api.authorization.AzAttributeResolver#equals}</code>.
     *
     * @param resolver The <code>AzAttributeResolver</code> instance to append.
     * @return true if the <code>AzAttributeResolver</code> was added,
     * false if the <code>AzAttributeResolver</code> was already in the list.
     * @throws IllegalArgumentException Given AzAttributeResolver was null.
     * @see AuthorizationService#appendAttributeResolver
     */
    @Override
    public boolean appendAttributeResolver(AzAttributeResolver resolver) {
        if ( null == resolver ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.resolver_null","The supplied Attribute Resolver is null."));
        }
        synchronized ( attributeResolvers ) {
            if ( !attributeResolvers.contains( resolver ) ) {
                attributeResolvers.add( resolver );
                return true;
            }
        }
        return false;
    }


    /**
     * Replaces the internal list of <code>AttributeResolver</code> instances
     * with the given list. If multiple equivalent instances exist in the given list,
     * only the first such instance will be inserted.
     *
     * @param resolverList Replacement list of <code>AzAttributeResolver</code> instances
     * @throws IllegalArgumentException Given AzAttributeResolver list was null.
     * @see AuthorizationService#setAttributeResolvers
     */
    @Override
    public void setAttributeResolvers(List<AzAttributeResolver> resolverList) {
        if ( null == resolverList ) {
            throw new IllegalArgumentException(localStrings.getLocalString("service.resolver_null","The supplied Attribute Resolver is null."));
        }

        synchronized ( attributeResolvers ) {
            attributeResolvers.clear();
            for ( AzAttributeResolver ar : resolverList ) {
                if ( (null != ar) && !attributeResolvers.contains(ar) ) {
                    attributeResolvers.add( ar );
                }
            }
        }
    }


    /**
     * Determines the current list of <code>AttributeResolver</code> instances,
     * in execution order.
     *
     * @return  The current list of AttributeResolver instances,
     * in execution order.
     * @see AuthorizationService#getAttributeResolvers
     */
    @Override
    public List<AzAttributeResolver> getAttributeResolvers() {
        return new ArrayList<AzAttributeResolver>( attributeResolvers );
    }


    /**
     * Removes all <code>AttributeResolver</code> instances from the current
     * internal list of <code>AttributeResolver</code> instances.
     *
     * @return true if any <code>AttributeResolver</code> instances were removed,
     * false if the list was empty.
     * @see AuthorizationService#removeAllAttributeResolvers
     */
    @Override
    public boolean removeAllAttributeResolvers() {
        synchronized ( attributeResolvers ) {
            if ( attributeResolvers.isEmpty() ) {
                return false;
            } else {
                attributeResolvers.clear();
                return true;
            }
        }
    }


    /**
     * Determines whether this service has been initialized.
     * @return The initialization state
     */
    final InitializationState getInitializationState() {
        return initialized;
    }


    /**
     * Determines the reason why the service failed to initialize.
     * @return The reason why the service failed to initialize,
     * null if initialization was successful or the failure reason was unknown.
     */
    final String getReasonInitializationFailed() {
        return reasonInitFailed;
    }


    /**
     * Checks whether this service is available.
     * @throws IllegalStateException This service is not available.
     */
    final void checkServiceAvailability() {
        if ( InitializationState.SUCCESS_INIT != getInitializationState() ) {
            throw new IllegalStateException(
                localStrings.getLocalString("service.atz.not_avail","The Authorization service is not available.") +
                getReasonInitializationFailed() );
        }
    }

  //
  // Log Messages
  //

  @LogMessageInfo(
      message = "Authorization Service has successfully initialized.",
      level = "INFO")
  private static final String ATZSVC_INITIALIZED = "SEC-SVCS-00100";

  @LogMessageInfo(
      message = "Authorization Service initialization failed, exception {0}, message {1}",
      level = "WARNING")
  private static final String ATZSVC_INIT_FAILED = "SEC-SVCS-00101";
}
TOP

Related Classes of org.glassfish.security.services.impl.authorization.AuthorizationServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.