From b17a103ee39c30027f2b455c6b3d605500cef637 Mon Sep 17 00:00:00 2001 From: Arjan Tijms Date: Thu, 3 Mar 2022 00:25:41 +0100 Subject: [PATCH] Implementation of new Jakarta Authentication methods Signed-off-by: Arjan Tijms --- .../config/factory/BaseAuthConfigFactory.java | 65 +++++++++- .../DefaultAuthConfigProvider.java | 117 ++++++++++++++++++ .../singlemodule/DefaultServerAuthConfig.java | 97 +++++++++++++++ .../DefaultServerAuthContext.java | 67 ++++++++++ .../com/sun/jaspic/config/FactoryTest.java | 12 -- 5 files changed, 343 insertions(+), 15 deletions(-) create mode 100644 appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultAuthConfigProvider.java create mode 100644 appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthConfig.java create mode 100644 appserver/security/jaspic-provider-framework/src/main/java/com/sun/jaspic/config/factory/singlemodule/DefaultServerAuthContext.java 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 aaadb881677..82156493d0b 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 @@ public abstract class BaseAuthConfigFactory extends AuthConfigFactory { 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 @@ public void refresh() { } } + /** + * Gets the app context ID from the servlet context. + * + *

+ * 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() { + @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() { + @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 00000000000..5f19a292884 --- /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 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 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 00000000000..b1d950ebcb2 --- /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 providerProperties; + private ServerAuthModule serverAuthModule; + + public DefaultServerAuthConfig(String layer, String appContext, CallbackHandler handler, + Map 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 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 00000000000..86ef0987b48 --- /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. + *

+ * 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. 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 4556ca1ea99..21778097cd5 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 @@ protected RegStoreFileParser getRegStore() { } } - @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 {