org.glassfish.security.services.common.SecurityAccessValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project for IBM JDK
/*
* 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