Implementation of new Jakarta Authentication methods
Signed-off-by: Arjan Tijms <arjan.tijms@gmail.com>
diff --git a/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/BaseAuthConfigFactory.java b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/BaseAuthConfigFactory.java
index aaadb88..8215649 100644
--- a/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/BaseAuthConfigFactory.java
+++ b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/BaseAuthConfigFactory.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation.
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -17,6 +18,8 @@
package com.sun.jaspic.config.factory;
import java.lang.reflect.Constructor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -30,12 +33,14 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.sun.jaspic.config.factory.singlemodule.DefaultAuthConfigProvider;
import com.sun.jaspic.config.helper.JASPICLogManager;
import jakarta.security.auth.message.config.AuthConfigFactory;
import jakarta.security.auth.message.config.AuthConfigProvider;
import jakarta.security.auth.message.config.RegistrationListener;
import jakarta.security.auth.message.module.ServerAuthModule;
+import jakarta.servlet.ServletContext;
/**
@@ -46,6 +51,8 @@
private static final Logger logger = Logger.getLogger(JASPICLogManager.JASPIC_LOGGER, JASPICLogManager.RES_BUNDLE);
+ private static final String CONTEXT_REGISTRATION_ID = "org.glassfish.security.message.registrationId";
+
private static final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
public static final Lock rLock = rwLock.readLock();
public static final Lock wLock = rwLock.writeLock();
@@ -370,18 +377,70 @@
}
}
+ /**
+ * Gets the app context ID from the servlet context.
+ *
+ * <p>
+ * The app context ID is the ID that Jakarta Authentication associates with the given application.
+ * In this case that given application is the web application corresponding to the
+ * ServletContext.
+ *
+ * @param context the servlet context for which to obtain the Jakarta Authentication app context ID
+ * @return the app context ID for the web application corresponding to the given context
+ */
+ public static String getAppContextID(ServletContext context) {
+ return context.getVirtualServerName() + " " + context.getContextPath();
+ }
+
@Override
public String registerServerAuthModule(ServerAuthModule serverAuthModule, Object context) {
- // TODO Auto-generated method stub
- return null;
+ if (!(context instanceof ServletContext)) {
+ return null;
+ }
+
+ ServletContext servletContext = (ServletContext) context;
+
+ // Register the factory-factory-factory for the SAM
+ String registrationId = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ @Override
+ public String run() {
+ return registerConfigProvider(
+ new DefaultAuthConfigProvider(serverAuthModule),
+ "HttpServlet",
+ getAppContextID(servletContext),
+ "Default single SAM authentication config provider");
+ }
+ });
+
+ // Remember the registration ID returned by the factory, so we can unregister the JASPIC module when the web module
+ // is undeployed. JASPIC being the low level API that it is won't do this automatically.
+ servletContext.setAttribute(CONTEXT_REGISTRATION_ID, registrationId);
+
+ return registrationId;
}
@Override
public void removeServerAuthModule(Object context) {
- // TODO Auto-generated method stub
+ if (!(context instanceof ServletContext)) {
+ return;
+ }
+ ServletContext servletContext = (ServletContext) context;
+
+ String registrationId = (String) servletContext.getAttribute(CONTEXT_REGISTRATION_ID);
+ if (!isEmpty(registrationId)) {
+ AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run() {
+ return removeRegistration(registrationId);
+ }
+ });
+ }
}
+ private static boolean isEmpty(String string) {
+ return string == null || string.isEmpty();
+ }
private AuthConfigProvider getConfigProviderUnderLock(String layer, String appContext,
RegistrationListener listener) {
diff --git a/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultAuthConfigProvider.java b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultAuthConfigProvider.java
new file mode 100644
index 0000000..5f19a29
--- /dev/null
+++ b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultAuthConfigProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation.
+ * Copyright (c) 2015, 2020 Oracle 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.jaspic.config.factory.singlemodule;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import jakarta.security.auth.message.AuthException;
+import jakarta.security.auth.message.config.AuthConfigFactory;
+import jakarta.security.auth.message.config.AuthConfigProvider;
+import jakarta.security.auth.message.config.ClientAuthConfig;
+import jakarta.security.auth.message.config.ServerAuthConfig;
+import jakarta.security.auth.message.config.ServerAuthContext;
+import jakarta.security.auth.message.module.ServerAuthModule;
+
+/**
+ * This class functions as a kind of factory-factory for {@link ServerAuthConfig} instances, which are by themselves factories
+ * for {@link ServerAuthContext} instances, which are delegates for the actual {@link ServerAuthModule} (SAM) that we're after.
+ *
+ * @author Arjan Tijms
+ */
+public class DefaultAuthConfigProvider implements AuthConfigProvider {
+
+ private static final String CALLBACK_HANDLER_PROPERTY_NAME = "authconfigprovider.client.callbackhandler";
+
+ private Map<String, String> providerProperties;
+ private ServerAuthModule serverAuthModule;
+
+ public DefaultAuthConfigProvider(ServerAuthModule serverAuthModule) {
+ this.serverAuthModule = serverAuthModule;
+ }
+
+ /**
+ * Constructor with signature and implementation that's required by API.
+ *
+ * @param properties provider properties
+ * @param factory the auth config factory
+ */
+ public DefaultAuthConfigProvider(Map<String, String> properties, AuthConfigFactory factory) {
+ this.providerProperties = properties;
+
+ // API requires self registration if factory is provided. Not clear
+ // where the "layer" (2nd parameter)
+ // and especially "appContext" (3rd parameter) values have to come from
+ // at this place.
+ if (factory != null) {
+ // If this method ever gets called, it may throw a SecurityException.
+ // Don't bother with a PrivilegedAction as we don't expect to ever be
+ // constructed this way.
+ factory.registerConfigProvider(this, null, null, "Auto registration");
+ }
+ }
+
+ /**
+ * The actual factory method that creates the factory used to eventually obtain the delegate for a SAM.
+ */
+ @Override
+ public ServerAuthConfig getServerAuthConfig(String layer, String appContext, CallbackHandler handler) throws AuthException,
+ SecurityException {
+ return new DefaultServerAuthConfig(layer, appContext, handler == null ? createDefaultCallbackHandler() : handler,
+ providerProperties, serverAuthModule);
+ }
+
+ @Override
+ public ClientAuthConfig getClientAuthConfig(String layer, String appContext, CallbackHandler handler) throws AuthException,
+ SecurityException {
+ return null;
+ }
+
+ @Override
+ public void refresh() {
+ }
+
+ /**
+ * Creates a default callback handler via the system property "authconfigprovider.client.callbackhandler", as seemingly
+ * required by the API (API uses wording "may" create default handler). TODO: Isn't
+ * "authconfigprovider.client.callbackhandler" JBoss specific?
+ *
+ * @return
+ * @throws AuthException
+ */
+ private CallbackHandler createDefaultCallbackHandler() throws AuthException {
+ String callBackClassName = System.getProperty(CALLBACK_HANDLER_PROPERTY_NAME);
+
+ if (callBackClassName == null) {
+ throw new AuthException("No default handler set via system property: " + CALLBACK_HANDLER_PROPERTY_NAME);
+ }
+
+ try {
+ return (CallbackHandler)
+ Thread.currentThread()
+ .getContextClassLoader()
+ .loadClass(callBackClassName)
+ .getDeclaredConstructor()
+ .newInstance();
+ } catch (Exception e) {
+ throw new AuthException(e.getMessage());
+ }
+ }
+
+}
diff --git a/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthConfig.java b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthConfig.java
new file mode 100644
index 0000000..b1d950e
--- /dev/null
+++ b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthConfig.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation.
+ * Copyright (c) 2015, 2020 Oracle 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.jaspic.config.factory.singlemodule;
+
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+
+import jakarta.security.auth.message.AuthException;
+import jakarta.security.auth.message.MessageInfo;
+import jakarta.security.auth.message.config.ServerAuthConfig;
+import jakarta.security.auth.message.config.ServerAuthContext;
+import jakarta.security.auth.message.module.ServerAuthModule;
+
+/**
+ * This class functions as a kind of factory for {@link ServerAuthContext} instances, which are delegates for the actual
+ * {@link ServerAuthModule} (SAM) that we're after.
+ *
+ * @author Arjan Tijms
+ */
+public class DefaultServerAuthConfig implements ServerAuthConfig {
+
+ private String layer;
+ private String appContext;
+ private CallbackHandler handler;
+ private Map<String, String> providerProperties;
+ private ServerAuthModule serverAuthModule;
+
+ public DefaultServerAuthConfig(String layer, String appContext, CallbackHandler handler,
+ Map<String, String> providerProperties, ServerAuthModule serverAuthModule) {
+ this.layer = layer;
+ this.appContext = appContext;
+ this.handler = handler;
+ this.providerProperties = providerProperties;
+ this.serverAuthModule = serverAuthModule;
+ }
+
+ @Override
+ public ServerAuthContext getAuthContext(String authContextID, Subject serviceSubject,
+ @SuppressWarnings("rawtypes") Map properties) throws AuthException {
+ return new DefaultServerAuthContext(handler, serverAuthModule);
+ }
+
+ // ### The methods below mostly just return what has been passed into the
+ // constructor.
+ // ### In practice they don't seem to be called
+
+ @Override
+ public String getMessageLayer() {
+ return layer;
+ }
+
+ /**
+ * It's not entirely clear what the difference is between the "application context identifier" (appContext) and the
+ * "authentication context identifier" (authContext). In early iterations of the specification, authContext was called
+ * "operation" and instead of the MessageInfo it was obtained by something called an "authParam".
+ */
+ @Override
+ public String getAuthContextID(MessageInfo messageInfo) {
+ return appContext;
+ }
+
+ @Override
+ public String getAppContext() {
+ return appContext;
+ }
+
+ @Override
+ public void refresh() {
+ }
+
+ @Override
+ public boolean isProtected() {
+ return false;
+ }
+
+ public Map<String, String> getProviderProperties() {
+ return providerProperties;
+ }
+
+}
diff --git a/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthContext.java b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthContext.java
new file mode 100644
index 0000000..86ef098
--- /dev/null
+++ b/appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthContext.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation.
+ * Copyright (c) 2015, 2020 Oracle 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.jaspic.config.factory.singlemodule;
+
+import java.util.Collections;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+
+import jakarta.security.auth.message.AuthException;
+import jakarta.security.auth.message.AuthStatus;
+import jakarta.security.auth.message.MessageInfo;
+import jakarta.security.auth.message.ServerAuth;
+import jakarta.security.auth.message.config.ServerAuthContext;
+import jakarta.security.auth.message.module.ServerAuthModule;
+
+/**
+ * The Server Authentication Context is an extra (required) indirection between the Application Server and the actual Server
+ * Authentication Module (SAM). This can be used to encapsulate any number of SAMs and either select one at run-time, invoke
+ * them all in order, etc.
+ * <p>
+ * Since this simple example only has a single SAM, we delegate directly to that one. Note that this {@link ServerAuthContext}
+ * and the {@link ServerAuthModule} (SAM) share a common base interface: {@link ServerAuth}.
+ *
+ * @author Arjan Tijms
+ */
+public class DefaultServerAuthContext implements ServerAuthContext {
+
+ private final ServerAuthModule serverAuthModule;
+
+ public DefaultServerAuthContext(CallbackHandler handler, ServerAuthModule serverAuthModule) throws AuthException {
+ this.serverAuthModule = serverAuthModule;
+ serverAuthModule.initialize(null, null, handler, Collections.<String, Object> emptyMap());
+ }
+
+ @Override
+ public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
+ throws AuthException {
+ return serverAuthModule.validateRequest(messageInfo, clientSubject, serviceSubject);
+ }
+
+ @Override
+ public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException {
+ return serverAuthModule.secureResponse(messageInfo, serviceSubject);
+ }
+
+ @Override
+ public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException {
+ serverAuthModule.cleanSubject(messageInfo, subject);
+ }
+
+}
diff --git a/appserver/security/jaspic-provider-framework/src/test/java/test/com/sun/jaspic/config/FactoryTest.java b/appserver/security/jaspic-provider-framework/src/test/java/test/com/sun/jaspic/config/FactoryTest.java
index 4556ca1..2177809 100644
--- a/appserver/security/jaspic-provider-framework/src/test/java/test/com/sun/jaspic/config/FactoryTest.java
+++ b/appserver/security/jaspic-provider-framework/src/test/java/test/com/sun/jaspic/config/FactoryTest.java
@@ -63,7 +63,6 @@
import jakarta.security.auth.message.config.RegistrationListener;
import jakarta.security.auth.message.config.ServerAuthConfig;
import jakarta.security.auth.message.config.ServerAuthContext;
-import jakarta.security.auth.message.module.ServerAuthModule;
/**
* @author Ron Monzillo
@@ -282,17 +281,6 @@
}
}
- @Override
- public String registerServerAuthModule(ServerAuthModule serverAuthModule, Object context) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void removeServerAuthModule(Object context) {
- // TODO Auto-generated method stub
-
- }
}
static class _Extends_ExtendsAuthConfigFactory extends _ExtendsBaseAuthConfigFactory {