Skip to content

Commit

Permalink
Small cleanup around auth config
Browse files Browse the repository at this point in the history
- AuthContext renamed to AuthContextImpl
- ClientAuthContext and ServerAuthContext have the new common parent,
  the AuthContext interface. More should be done later in own PR,
  now I just needed to know classes I am working with.
- this module is really ugly, should be radically refactored or removed.
- years ago I had to implement login module and realm - be careful when
  refactoring, protected fields are used by other implementations, so the
  refactoring will be a breaking change. This one shouldn't.

Signed-off-by: David Matějček <david.matejcek@omnifish.ee>
  • Loading branch information
dmatej committed Sep 18, 2022
1 parent 89b1064 commit b02a650
Show file tree
Hide file tree
Showing 23 changed files with 502 additions and 527 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.sun.enterprise.deployment.annotation.context.EjbContext;
import com.sun.enterprise.deployment.annotation.context.WebBundleContext;
import com.sun.enterprise.deployment.annotation.context.WebComponentContext;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.deployment.util.TypeUtil;

import jakarta.annotation.security.DenyAll;
Expand All @@ -39,6 +40,7 @@
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.apf.AnnotationInfo;
import org.glassfish.apf.AnnotationProcessorException;
Expand All @@ -52,6 +54,7 @@
*/
abstract class AbstractAuthAnnotationHandler extends AbstractCommonAttributeHandler
implements PostProcessor<EjbContext> {
private static final Logger LOG = DOLUtils.getDefaultLogger();

/**
* This method processes the EJB Security for the given Annotation.
Expand Down Expand Up @@ -139,19 +142,19 @@ public void postProcessAnnotation(AnnotationInfo ainfo, EjbContext ejbContext) t
EjbDescriptor ejbDesc = ejbContext.getDescriptor();
Annotation authAnnotation = ainfo.getAnnotation();

if (!ejbContext.isInherited()
&& (ejbDesc.getMethodPermissionsFromDD() == null || ejbDesc.getMethodPermissionsFromDD().isEmpty())) {
for (MethodDescriptor md : getMethodAllDescriptors(ejbDesc)) {
processEjbMethodSecurity(authAnnotation, md, ejbDesc);
}
} else {
if (ejbContext.isInherited()
|| (ejbDesc.getMethodPermissionsFromDD() != null && !ejbDesc.getMethodPermissionsFromDD().isEmpty())) {
Class<?> classAn = (Class<?>) ainfo.getAnnotatedElement();
for (MethodDescriptor md : ejbDesc.getSecurityBusinessMethodDescriptors()) {
// override by existing info
if (classAn.equals(ejbContext.getDeclaringClass(md)) && !hasMethodPermissionsFromDD(md, ejbDesc)) {
processEjbMethodSecurity(authAnnotation, md, ejbDesc);
}
}
} else {
for (MethodDescriptor md : getMethodAllDescriptors(ejbDesc)) {
processEjbMethodSecurity(authAnnotation, md, ejbDesc);
}
}
}

Expand Down Expand Up @@ -221,13 +224,16 @@ private boolean hasMethodPermissionsFromDD(MethodDescriptor methodDesc, EjbDescr
for (List<MethodDescriptor> mdObjs : methodPermissionsFromDD.values()) {
for (MethodDescriptor md : mdObjs) {
for (MethodDescriptor style3Md : md.doStyleConversion(ejbDesc, allMethods)) {
LOG.log(Level.FINEST, "Comparing style3Md: {0} and methodDesc: {1}", new Object[] {style3Md, methodDesc});
if (methodDesc.equals(style3Md)) {
LOG.info("Returning true.");
return true;
}
}
}
}
}
LOG.info("Returning false.");
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ protected void processEjbMethodSecurity(Annotation authAnnotation, MethodDescrip
RolesAllowed rolesAllowedAn = (RolesAllowed) authAnnotation;
for (String roleName : rolesAllowedAn.value()) {
Role role = new Role(roleName);
// add role if not exists
ejbDesc.getEjbBundleDescriptor().addRole(role);
ejbDesc.addPermissionedMethod(new MethodPermission(role), md);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ protected void accept(EjbReference ejbRef) {
throw new RuntimeException("Error: Unresolved <ejb-link>: "+linkName);
} else {
final ArchiveType moduleType = ejbRef.getReferringBundleDescriptor().getModuleType();
if(moduleType != null && moduleType.equals(DOLUtils.carType())) {
if (moduleType != null && moduleType.equals(DOLUtils.carType())) {
// Because no annotation processing is done within ACC runtime, this case typically
// arises for remote @EJB annotations, so don't log it as warning.
if (LOG.isLoggable(Level.FINE)) {
Expand Down Expand Up @@ -879,7 +879,7 @@ protected void computeRunAsPrincipalDefault(RunAsIdentityDescriptor runAs,
String principalName = null;
String roleName = runAs.getRoleName();

final Subject fs = (Subject)application.getRoleMapper().getRoleToSubjectMapping().get(roleName);
final Subject fs = application.getRoleMapper().getRoleToSubjectMapping().get(roleName);
if (fs != null) {
principalName = (String)AccessController.doPrivileged(new PrivilegedAction() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022 Eclipse Foundation and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -16,206 +16,27 @@

package com.sun.enterprise.security.jauth;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.login.AppConfigurationEntry;

/**
* Shared logic from Client and ServerAuthContext reside here.
* Authentication context for login modules.
*
* @author David Matejcek
*/
final class AuthContext {

static final String INIT = "initialize";
static final String DISPOSE_SUBJECT = "disposeSubject";

static final String SECURE_REQUEST = "secureRequest";
static final String VALIDATE_RESPONSE = "validateResponse";

static final String VALIDATE_REQUEST = "validateRequest";
static final String SECURE_RESPONSE = "secureResponse";

// managesSessions method is implemented by looking for
// corresponding option value in module configuration
static final String MANAGES_SESSIONS = "managesSessions";
static final String MANAGES_SESSIONS_OPTION = "managessessions";

private ConfigFile.Entry[] entries;
private Logger logger;

AuthContext(ConfigFile.Entry[] entries, Logger logger) throws AuthException {

this.entries = entries;
this.logger = logger;
}
public interface AuthContext {

/**
* Invoke modules according to configuration
* Dispose of the Subject (remove Principals or credentials from the Subject object that were
* stored during validation.
* <p>
* This method invokes configured modules to dispose the Subject.
*
* @param subject the subject to be disposed.
* @param sharedState a Map for modules to save state across a sequence of calls
* from <code>validateRequest</code> to <code>secureResponse</code> to
* <code>disposeSubject</code>.
* @throws AuthException if the operation failed.
*/
Object[] invoke(final String methodName, final Object[] args) throws AuthException {

// invoke modules in a doPrivileged
final Object rValues[] = new Object[entries.length];

try {
java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction() {
@Override
public Object run() throws AuthException {
invokePriv(methodName, args, rValues);
return null;
}
});
} catch (java.security.PrivilegedActionException pae) {
if (pae.getException() instanceof AuthException) {
throw (AuthException) pae.getException();
}
AuthException ae = new AuthException();
ae.initCause(pae.getException());
throw ae;
}
return rValues;
}

void invokePriv(String methodName, Object[] args, Object[] rValues) throws AuthException {

// special treatment for managesSessions until the module
// interface can be extended.
if (methodName.equals(AuthContext.MANAGES_SESSIONS)) {
for (int i = 0; i < entries.length; i++) {
Map options = entries[i].getOptions();
String mS = (String) options.get(AuthContext.MANAGES_SESSIONS_OPTION);
rValues[i] = Boolean.valueOf(mS);
}
return;
}

boolean success = false;
AuthException firstRequiredError = null;
AuthException firstError = null;

// XXX no way to reverse module invocation

for (int i = 0; i < entries.length; i++) {

// get initialized module instance

Object module = entries[i].module;

// invoke the module

try {
Method[] mArray = module.getClass().getMethods();
for (Method element : mArray) {
if (element.getName().equals(methodName)) {

// invoke module
rValues[i] = element.invoke(module, args);

// success -
// return if SUFFICIENT and no previous REQUIRED errors

if (firstRequiredError == null
&& entries[i].getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT) {

if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine(entries[i].getLoginModuleName() + "." + methodName + " SUFFICIENT success");
}

return;
}

if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine(entries[i].getLoginModuleName() + "." + methodName + " success");
}

success = true;
break;
}
}

if (!success) {
// PLEASE NOTE:
// this exception will be thrown if any module
// in the context does not support the method.
NoSuchMethodException nsme = new NoSuchMethodException(
"module " + module.getClass().getName() + " does not implement " + methodName);
AuthException ae = new AuthException();
ae.initCause(nsme);
throw ae;
}
} catch (IllegalAccessException iae) {
AuthException ae = new AuthException();
ae.initCause(iae);
throw ae;
} catch (InvocationTargetException ite) {

// failure cases

AuthException ae;

if (ite.getCause() instanceof AuthException) {
ae = (AuthException) ite.getCause();
} else {
ae = new AuthException();
ae.initCause(ite.getCause());
}

if (entries[i].getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUISITE) {

if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine(entries[i].getLoginModuleName() + "." + methodName + " REQUISITE failure");
}

// immediately throw exception

if (firstRequiredError != null) {
throw firstRequiredError;
}
throw ae;

}
if (entries[i].getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUIRED) {

if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine(entries[i].getLoginModuleName() + "." + methodName + " REQUIRED failure");
}

// save exception and continue

if (firstRequiredError == null) {
firstRequiredError = ae;
}

} else {

if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine(entries[i].getLoginModuleName() + "." + methodName + " OPTIONAL failure");
}

// save exception and continue

if (firstError == null) {
firstError = ae;
}
}
}
}

// done invoking entire stack of modules

if (firstRequiredError != null) {
throw firstRequiredError;
}
if (firstError != null && !success) {
throw firstError;
}
void disposeSubject(javax.security.auth.Subject subject, Map sharedState) throws AuthException;

// if no errors, return gracefully
if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine("overall " + methodName + " success");
}
}
}

0 comments on commit b02a650

Please sign in to comment.