All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.security.services.common.SecurityAccessValidator Maven / Gradle / Ivy

There is a newer version: 4.1.2.181
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 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.common;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Iterator;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;

import org.glassfish.hk2.api.ValidationInformation;
import org.glassfish.hk2.api.Validator;
import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.Descriptor;

import com.sun.enterprise.util.LocalStringManagerImpl;


public class SecurityAccessValidator implements Validator {

    private static final Logger LOG = SecurityAccessValidationService._theLog;
    private static LocalStringManagerImpl localStrings =
        new LocalStringManagerImpl(SecurityAccessValidator.class);

    
    @Override
    public boolean validate(ValidationInformation info) {

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("ValidationInformation info= " + info);
        }

        switch (info.getOperation()) {
        case BIND:
        case UNBIND:
            return validateBindAndUnbind(info);
        case LOOKUP:
            return validateLookup(info.getCandidate(), info.getInjectee());
        default:
            return false;
        }

    }

    private boolean isSecureAnnotated(ValidationInformation info) {

        Descriptor d = info.getCandidate();

        Set qualifiers = d.getQualifiers();
        if (qualifiers != null && qualifiers.size() != 0) {
            for (String s : qualifiers) {
                if (Secure.class.getCanonicalName().equals(s)) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("The instance is annotated with \'Secure\': "
                                + info);
                    }
                    return true;
                }
            }
        }

        return false;

    }

    private boolean validateBindAndUnbind(ValidationInformation info) {

        // do nothing if the instance is not annotated with 'Secure'
        if (!isSecureAnnotated(info))
            return true;

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("validateBindAndUnbind," + " injectee= "
                    + info.getInjectee());
        }

        return validateLookup(info.getCandidate(), info.getInjectee());
    }

    private boolean validateLookup(ActiveDescriptor candidate,
            Injectee injectee) {

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Lookup candiate =" + candidate + ", injectee= "
                    + injectee);
        }

        if (!candidate.isReified()) {
            // not yet really injected yet, so not to check perm
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Lookup candiate is not reified yet");
            }
            return true;
        } else {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Lookup candiate is reified, candidate = " + candidate);
            }
        }        
        
        Set contracts = candidate.getAdvertisedContracts();

        if (contracts == null)
            return true;

        Map> md = candidate.getMetadata();
        
        if (LOG.isLoggable(Level.FINE)) {            
            Iterator>> itr = md.entrySet().iterator();
            while (itr.hasNext()) {
                Map.Entry> entry = itr.next();
                String k = entry.getKey();
                for (String v : entry.getValue()) {
                    LOG.fine("$$ key= " + k + ", value= " + v);
                }                                
            }
        }
        
        Permission perm = null;
        List names = md.get(Secure.NAME);
        if (names == null || names.isEmpty()) {

            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Perm name is empty, will use default value");
            }
            
            //the 'Secure' annotation did not specify a accessPermissionName, use default accessPermissionName name
            perm = getAccessPermision(Secure.DEFAULT_PERM_NAME, null);
            
        } else {
            String permName = names.get(0);
            perm = getAccessPermision(permName, null);
        }
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("The permission to be protected = " + perm);
        }

        boolean check_result = false;
        if (injectee == null) {
            // lookup style check
            
            Class caller = getServiceLookupCaller();
            
            check_result = checkPerm(perm, caller);
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Lookup, checked perm for = " + perm + ", result= "
                        + check_result);
            }
        } else {
            // injection style check
            check_result = validateInjection(candidate, injectee, perm);
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Injection, checked perm for = " + perm + ", result= "
                        + check_result);
            }
        }

        return check_result;
    }
    
    
    //temporary alternative fixing to JIRA-HK2:116
    private Class getServiceLookupCaller() {
/*
        StackTraceElement[] steArr = new Exception().getStackTrace();
        
        for (int i = 0; i < steArr.length; i++ ) {
            StackTraceElement elm = steArr[i];
            
            if (elm.getClassName().equals("org.jvnet.hk2.internal.ServiceLocatorImpl") &&
                    (elm.getMethodName().equals("getService") ||
                     elm.getMethodName().equals("getAllServices") ||
                     elm.getMethodName().equals("getServiceHandle") ||
                     elm.getMethodName().equals("getAllServiceHandles") ||
                     elm.getMethodName().equals("create") ||
                     elm.getMethodName().equals("createAndInitialize") ||
                     elm.getMethodName().equals("shutdown")
                     
               )) {

                if (LOG.isLoggable(Level.FINE)) {
                    LOG.fine("Found the service locator, classname= " 
                            + steArr[i+1].getClassName() + ", ste =" + steArr[i+1]);
                }

                //after finding the 1st service locator, then look for the class which is not ServiceLocatorImpl
                System.out.println("%%%%found the locator");
                for (int j = i+1; j < steArr.length; j++ ) {
                    StackTraceElement elmj = steArr[j];
                    if (elmj.getClassName().startsWith("org.jvnet.hk2.internal."))  //by pass all hk2 classes to find the caller
                        continue;
                    else {
                        StackTraceElement caller = elmj;
                        //found the caller class which is not ServiceLocatorImpl
                        System.out.println("%%%caller Class name= " + caller.getClassName() + ", caller ste =" + caller + 
                                ", method=" + caller.getMethodName());                
                        try {
                            return Class.forName(caller.getClassName(), true, Thread.currentThread().getContextClassLoader());
                        } catch (ClassNotFoundException e) {

                            try {
                                return Class.forName(caller.getClassName());
                            } catch (ClassNotFoundException e1) {
                                // TODO Auto-generated catch block
                                //e1.printStackTrace();
                                LOG.warning(localStrings.getLocalString("sec.validate.lookup.noclass",
                                        "Lookup Class not found in classpath: {0}", caller.getClassName()));
                                throw new RuntimeException(e);
                            }
                            
                        }
                    }
                }
            }
        }

        System.out.println("%%%caller Class= null");
        LOG.warning(localStrings.getLocalString("sec.validate.lookup.fail", "Cannot find the looup caller class"));
*/
        return null;
        
    }

    private boolean checkPerm(Permission p, Class caller) {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Checked perm for = " + p);
        }

        
        try {
            if (caller != null) {
                ProtectionDomain pd = this.getCallerProtDomain(caller);
                pd.implies(p);
            } else
                AccessController.checkPermission(p);
            
        } catch (SecurityException e) {
            
            LOG.warning(localStrings.getLocalString(
                    "sec.validate.lookup.deny", "Check Permission failed in lookup for permission = {0}",  p));

            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Check Permission failed, perm= " + p + ", message = "
                        + e.getMessage());
            }
            throw e;
        }

        return true;
    }


    private boolean validateInjection(ActiveDescriptor candidate,
            Injectee injectee, Permission p) {

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Injectee =" + injectee + ", permission= " + p);
        }

        // If this is an Inject, get the protection domain of the injectee
        Class injecteeClass = injectee.getInjecteeClass();

        ProtectionDomain pd = getCallerProtDomain(injecteeClass);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Protection domain code src= " + pd.getCodeSource());
        }

        if (!pd.implies(p)) {
            
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("permission check failed for " + injectee + ", to get perm " + p + ", for candidate "
                        + candidate);
            }

            throw new AccessControlException(localStrings.getLocalString("sec.validate.injection.deny",   
                    "Access denied for injectee {0} to get permission {1}.", injectee, p));
                    
        } else {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("permission check success for " + injectee
                        + " to get " + candidate);
            }
        }

        return true;
    }

    private ProtectionDomain getCallerProtDomain(final Class caller) {
        ProtectionDomain pd = AccessController
                .doPrivileged(new PrivilegedAction() {
                    @Override
                    public ProtectionDomain run() {
                        return caller.getProtectionDomain();
                    }
                });

        return pd;
    }


    /**
     * The permission to be checked
     * 
     * @return permission to be checked
     */
    private Permission getAccessPermision(String protectName, String action) {
        return new SecureServiceAccessPermission(protectName, action);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy