This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,514 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.security.auth.message.config.AuthConfigFactory;
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.RegistrationListener;
import org.apache.catalina.Globals;
import org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Provider;
import org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Providers;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;
public class AuthConfigFactoryImpl extends AuthConfigFactory {
private final Log log = LogFactory.getLog(AuthConfigFactoryImpl.class); // must not be static
private static final StringManager sm = StringManager.getManager(AuthConfigFactoryImpl.class);
private static final String CONFIG_PATH = "conf/jaspic-providers.xml";
private static final File CONFIG_FILE =
new File(System.getProperty(Globals.CATALINA_BASE_PROP), CONFIG_PATH);
private static final Object CONFIG_FILE_LOCK = new Object();
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static String DEFAULT_REGISTRATION_ID = getRegistrationID(null, null);
private final Map<String,RegistrationContextImpl> layerAppContextRegistrations =
new ConcurrentHashMap<>();
private final Map<String,RegistrationContextImpl> appContextRegistrations =
new ConcurrentHashMap<>();
private final Map<String,RegistrationContextImpl> layerRegistrations =
new ConcurrentHashMap<>();
// Note: Although there will only ever be a maximum of one entry in this
// Map, use a ConcurrentHashMap for consistency
private final Map<String,RegistrationContextImpl> defaultRegistration =
new ConcurrentHashMap<>(1);
public AuthConfigFactoryImpl() {
loadPersistentRegistrations();
}
@Override
public AuthConfigProvider getConfigProvider(String layer, String appContext,
RegistrationListener listener) {
RegistrationContextImpl registrationContext =
findRegistrationContextImpl(layer, appContext);
if (registrationContext != null) {
if (listener != null) {
RegistrationListenerWrapper wrapper = new RegistrationListenerWrapper(
layer, appContext, listener);
registrationContext.addListener(wrapper);
}
return registrationContext.getProvider();
}
return null;
}
@Override
public String registerConfigProvider(String className,
@SuppressWarnings("rawtypes") Map properties, String layer, String appContext,
String description) {
String registrationID =
doRegisterConfigProvider(className, properties, layer, appContext, description);
savePersistentRegistrations();
return registrationID;
}
@SuppressWarnings("unchecked")
private String doRegisterConfigProvider(String className,
@SuppressWarnings("rawtypes") Map properties, String layer, String appContext,
String description) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("authConfigFactoryImpl.registerClass",
className, layer, appContext));
}
AuthConfigProvider provider = null;
if (className != null) {
provider = createAuthConfigProvider(className, properties);
}
String registrationID = getRegistrationID(layer, appContext);
RegistrationContextImpl registrationContextImpl = new RegistrationContextImpl(
layer, appContext, description, true, provider, properties);
addRegistrationContextImpl(layer, appContext, registrationID, registrationContextImpl);
return registrationID;
}
private AuthConfigProvider createAuthConfigProvider(String className,
@SuppressWarnings("rawtypes") Map properties) throws SecurityException {
Class<?> clazz = null;
AuthConfigProvider provider = null;
try {
clazz = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
// Ignore so the re-try below can proceed
}
try {
if (clazz == null) {
clazz = Class.forName(className);
}
Constructor<?> constructor = clazz.getConstructor(Map.class, AuthConfigFactory.class);
provider = (AuthConfigProvider) constructor.newInstance(properties, null);
} catch (ReflectiveOperationException | IllegalArgumentException e) {
throw new SecurityException(e);
}
return provider;
}
@Override
public String registerConfigProvider(AuthConfigProvider provider, String layer,
String appContext, String description) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("authConfigFactoryImpl.registerInstance",
provider.getClass().getName(), layer, appContext));
}
String registrationID = getRegistrationID(layer, appContext);
RegistrationContextImpl registrationContextImpl = new RegistrationContextImpl(
layer, appContext, description, false, provider, null);
addRegistrationContextImpl(layer, appContext, registrationID, registrationContextImpl);
return registrationID;
}
private void addRegistrationContextImpl(String layer, String appContext,
String registrationID, RegistrationContextImpl registrationContextImpl) {
RegistrationContextImpl previous = null;
// Add the registration, noting any registration it replaces
if (layer != null && appContext != null) {
previous = layerAppContextRegistrations.put(registrationID, registrationContextImpl);
} else if (layer == null && appContext != null) {
previous = appContextRegistrations.put(registrationID, registrationContextImpl);
} else if (layer != null && appContext == null) {
previous = layerRegistrations.put(registrationID, registrationContextImpl);
} else {
previous = defaultRegistration.put(registrationID, registrationContextImpl);
}
if (previous == null) {
// No match with previous registration so need to check listeners
// for all less specific registrations to see if they need to be
// notified of this new registration. That there is no exact match
// with a previous registration allows a few short-cuts to be taken
if (layer != null && appContext != null) {
// Need to check existing appContext registrations
// (and layer and default)
// appContext must match
RegistrationContextImpl registration =
appContextRegistrations.get(getRegistrationID(null, appContext));
if (registration != null) {
for (RegistrationListenerWrapper wrapper : registration.listeners) {
if (layer.equals(wrapper.getMessageLayer()) &&
appContext.equals(wrapper.getAppContext())) {
registration.listeners.remove(wrapper);
wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
}
}
}
}
if (appContext != null) {
// Need to check existing layer registrations
// (and default)
// Need to check registrations for all layers
for (RegistrationContextImpl registration : layerRegistrations.values()) {
for (RegistrationListenerWrapper wrapper : registration.listeners) {
if (appContext.equals(wrapper.getAppContext())) {
registration.listeners.remove(wrapper);
wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
}
}
}
}
if (layer != null || appContext != null) {
// Need to check default
for (RegistrationContextImpl registration : defaultRegistration.values()) {
for (RegistrationListenerWrapper wrapper : registration.listeners) {
if (appContext != null && appContext.equals(wrapper.getAppContext()) ||
layer != null && layer.equals(wrapper.getMessageLayer())) {
registration.listeners.remove(wrapper);
wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
}
}
}
}
} else {
// Replaced an existing registration so need to notify those listeners
for (RegistrationListenerWrapper wrapper : previous.listeners) {
previous.listeners.remove(wrapper);
wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
}
}
}
@Override
public boolean removeRegistration(String registrationID) {
RegistrationContextImpl registration = null;
if (DEFAULT_REGISTRATION_ID.equals(registrationID)) {
registration = defaultRegistration.remove(registrationID);
}
if (registration == null) {
registration = layerAppContextRegistrations.remove(registrationID);
}
if (registration == null) {
registration = appContextRegistrations.remove(registrationID);
}
if (registration == null) {
registration = layerRegistrations.remove(registrationID);
}
if (registration == null) {
return false;
} else {
for (RegistrationListenerWrapper wrapper : registration.listeners) {
wrapper.getListener().notify(wrapper.getMessageLayer(), wrapper.getAppContext());
}
if (registration.isPersistent()) {
savePersistentRegistrations();
}
return true;
}
}
@Override
public String[] detachListener(RegistrationListener listener, String layer, String appContext) {
String registrationID = getRegistrationID(layer, appContext);
RegistrationContextImpl registrationContext = findRegistrationContextImpl(layer, appContext);
if (registrationContext != null && registrationContext.removeListener(listener)) {
return new String[] { registrationID };
}
return EMPTY_STRING_ARRAY;
}
@Override
public String[] getRegistrationIDs(AuthConfigProvider provider) {
List<String> result = new ArrayList<>();
if (provider == null) {
result.addAll(layerAppContextRegistrations.keySet());
result.addAll(appContextRegistrations.keySet());
result.addAll(layerRegistrations.keySet());
if (!defaultRegistration.isEmpty()) {
result.add(DEFAULT_REGISTRATION_ID);
}
} else {
findProvider(provider, layerAppContextRegistrations, result);
findProvider(provider, appContextRegistrations, result);
findProvider(provider, layerRegistrations, result);
findProvider(provider, defaultRegistration, result);
}
return result.toArray(EMPTY_STRING_ARRAY);
}
private void findProvider(AuthConfigProvider provider,
Map<String,RegistrationContextImpl> registrations, List<String> result) {
for (Entry<String,RegistrationContextImpl> entry : registrations.entrySet()) {
if (provider.equals(entry.getValue().getProvider())) {
result.add(entry.getKey());
}
}
}
@Override
public RegistrationContext getRegistrationContext(String registrationID) {
RegistrationContext result = defaultRegistration.get(registrationID);
if (result == null) {
result = layerAppContextRegistrations.get(registrationID);
}
if (result == null) {
result = appContextRegistrations.get(registrationID);
}
if (result == null) {
result = layerRegistrations.get(registrationID);
}
return result;
}
@Override
public void refresh() {
loadPersistentRegistrations();
}
private static String getRegistrationID(String layer, String appContext) {
if (layer != null && layer.length() == 0) {
throw new IllegalArgumentException(
sm.getString("authConfigFactoryImpl.zeroLengthMessageLayer"));
}
if (appContext != null && appContext.length() == 0) {
throw new IllegalArgumentException(
sm.getString("authConfigFactoryImpl.zeroLengthAppContext"));
}
return (layer == null ? "" : layer) + ":" + (appContext == null ? "" : appContext);
}
private void loadPersistentRegistrations() {
synchronized (CONFIG_FILE_LOCK) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("authConfigFactoryImpl.load",
CONFIG_FILE.getAbsolutePath()));
}
if (!CONFIG_FILE.isFile()) {
return;
}
Providers providers = PersistentProviderRegistrations.loadProviders(CONFIG_FILE);
for (Provider provider : providers.getProviders()) {
doRegisterConfigProvider(provider.getClassName(), provider.getProperties(),
provider.getLayer(), provider.getAppContext(), provider.getDescription());
}
}
}
private void savePersistentRegistrations() {
synchronized (CONFIG_FILE_LOCK) {
Providers providers = new Providers();
savePersistentProviders(providers, layerAppContextRegistrations);
savePersistentProviders(providers, appContextRegistrations);
savePersistentProviders(providers, layerRegistrations);
savePersistentProviders(providers, defaultRegistration);
PersistentProviderRegistrations.writeProviders(providers, CONFIG_FILE);
}
}
private void savePersistentProviders(Providers providers,
Map<String,RegistrationContextImpl> registrations) {
for (Entry<String,RegistrationContextImpl> entry : registrations.entrySet()) {
savePersistentProvider(providers, entry.getValue());
}
}
private void savePersistentProvider(Providers providers,
RegistrationContextImpl registrationContextImpl) {
if (registrationContextImpl != null && registrationContextImpl.isPersistent()) {
Provider provider = new Provider();
provider.setAppContext(registrationContextImpl.getAppContext());
if (registrationContextImpl.getProvider() != null) {
provider.setClassName(registrationContextImpl.getProvider().getClass().getName());
}
provider.setDescription(registrationContextImpl.getDescription());
provider.setLayer(registrationContextImpl.getMessageLayer());
for (Entry<String,String> property : registrationContextImpl.getProperties().entrySet()) {
provider.addProperty(property.getKey(), property.getValue());
}
providers.addProvider(provider);
}
}
private RegistrationContextImpl findRegistrationContextImpl(String layer, String appContext) {
RegistrationContextImpl result;
result = layerAppContextRegistrations.get(getRegistrationID(layer, appContext));
if (result == null) {
result = appContextRegistrations.get(getRegistrationID(null, appContext));
}
if (result == null) {
result = layerRegistrations.get(getRegistrationID(layer, null));
}
if (result == null) {
result = defaultRegistration.get(DEFAULT_REGISTRATION_ID);
}
return result;
}
private static class RegistrationContextImpl implements RegistrationContext {
private RegistrationContextImpl(String messageLayer, String appContext, String description,
boolean persistent, AuthConfigProvider provider, Map<String,String> properties) {
this.messageLayer = messageLayer;
this.appContext = appContext;
this.description = description;
this.persistent = persistent;
this.provider = provider;
Map<String,String> propertiesCopy = new HashMap<>();
if (properties != null) {
propertiesCopy.putAll(properties);
}
this.properties = Collections.unmodifiableMap(propertiesCopy);
}
private final String messageLayer;
private final String appContext;
private final String description;
private final boolean persistent;
private final AuthConfigProvider provider;
private final Map<String,String> properties;
private final List<RegistrationListenerWrapper> listeners = new CopyOnWriteArrayList<>();
@Override
public String getMessageLayer() {
return messageLayer;
}
@Override
public String getAppContext() {
return appContext;
}
@Override
public String getDescription() {
return description;
}
@Override
public boolean isPersistent() {
return persistent;
}
private AuthConfigProvider getProvider() {
return provider;
}
private void addListener(RegistrationListenerWrapper listener) {
if (listener != null) {
listeners.add(listener);
}
}
private Map<String,String> getProperties() {
return properties;
}
private boolean removeListener(RegistrationListener listener) {
boolean result = false;
for (RegistrationListenerWrapper wrapper : listeners) {
if (wrapper.getListener().equals(listener)) {
listeners.remove(wrapper);
result = true;
}
}
return result;
}
}
private static class RegistrationListenerWrapper {
private final String messageLayer;
private final String appContext;
private final RegistrationListener listener;
public RegistrationListenerWrapper(String messageLayer, String appContext,
RegistrationListener listener) {
this.messageLayer = messageLayer;
this.appContext = appContext;
this.listener = listener;
}
public String getMessageLayer() {
return messageLayer;
}
public String getAppContext() {
return appContext;
}
public RegistrationListener getListener() {
return listener;
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.io.IOException;
import java.security.Principal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.callback.GroupPrincipalCallback;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;
/**
* Implemented as a singleton since the class is stateless.
*/
public class CallbackHandlerImpl implements CallbackHandler {
private static final StringManager sm = StringManager.getManager(CallbackHandlerImpl.class);
private static CallbackHandler instance;
static {
instance = new CallbackHandlerImpl();
}
public static CallbackHandler getInstance() {
return instance;
}
private CallbackHandlerImpl() {
// Hide default constructor
}
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
String name = null;
Principal principal = null;
Subject subject = null;
String[] groups = null;
if (callbacks != null) {
// Need to combine data from multiple callbacks so use this to hold
// the data
// Process the callbacks
for (Callback callback : callbacks) {
if (callback instanceof CallerPrincipalCallback) {
CallerPrincipalCallback cpc = (CallerPrincipalCallback) callback;
name = cpc.getName();
principal = cpc.getPrincipal();
subject = cpc.getSubject();
} else if (callback instanceof GroupPrincipalCallback) {
GroupPrincipalCallback gpc = (GroupPrincipalCallback) callback;
groups = gpc.getGroups();
} else {
// This is a singleton so need to get correct Logger for
// current TCCL
Log log = LogFactory.getLog(CallbackHandlerImpl.class);
log.error(sm.getString("callbackHandlerImpl.jaspicCallbackMissing",
callback.getClass().getName()));
}
}
// Create the GenericPrincipal
Principal gp = getPrincipal(principal, name, groups);
if (subject != null && gp != null) {
subject.getPrivateCredentials().add(gp);
}
}
}
private Principal getPrincipal(Principal principal, String name, String[] groups) {
// If the Principal is cached in the session JASPIC may simply return it
if (principal instanceof GenericPrincipal) {
return principal;
}
if (name == null && principal != null) {
name = principal.getName();
}
if (name == null) {
return null;
}
List<String> roles;
if (groups == null || groups.length == 0) {
roles = Collections.emptyList();
} else {
roles = Arrays.asList(groups);
}
return new GenericPrincipal(name, null, roles, principal);
}
}

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.load=Loading persistent provider registrations from [{0}]
authConfigFactoryImpl.registerClass=Registering class [{0}] for layer [{1}] and application context [{2}]
authConfigFactoryImpl.registerInstance=Registering instance of type[{0}] for layer [{1}] and application context [{2}]
authConfigFactoryImpl.zeroLengthAppContext=A zero length application context name is not valid
authConfigFactoryImpl.zeroLengthMessageLayer=A zero length message layer name is not valid
callbackHandlerImpl.jaspicCallbackMissing=Unsupported JASPIC callback of type [{0}] received which was ignored
jaspicAuthenticator.authenticate=Authenticating request for [{0}] via JASPIC
persistentProviderRegistrations.deleteFail=The temporary file [{0}] cannot be deleted
persistentProviderRegistrations.existsDeleteFail=The temporary file [{0}] already exists and cannot be deleted
persistentProviderRegistrations.moveFail=Failed to move [{0}] to [{1}]
simpleServerAuthConfig.noModules="No ServerAuthModules configured"

View File

@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.zeroLengthAppContext=Ein leerer Name für einen Applikationskontext ist nicht erlaubt.
persistentProviderRegistrations.existsDeleteFail=Die temporäre Datei [{0}] existiert bereits und kann nicht gelöscht werden

View File

@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.zeroLengthAppContext=Un nombre de aplicación con nombre de contexto de longitud cero no es válido
persistentProviderRegistrations.existsDeleteFail=El archivo temporal [{0}] ya existe y no puede ser borrado

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.load=Chargement des enregistrements pour le fournisseurs persistants à partir de [{0}]
authConfigFactoryImpl.registerClass=Enregistrement de la classe [{0}] pour la couche [{1}] et le contexte d''application [{2}]
authConfigFactoryImpl.registerInstance=Enregistrement de l''instance de type [{0}] pour la couche [{1}] et le contexte d''application [{2}]
authConfigFactoryImpl.zeroLengthAppContext=Un nom de contexte vide n'est pas valide
authConfigFactoryImpl.zeroLengthMessageLayer=Un message vide de nom de couche est invalide
callbackHandlerImpl.jaspicCallbackMissing=Le rappel (callback) JASPIC de type [{0}] reçu n''est pas supporté et a été ignoré
jaspicAuthenticator.authenticate=Authentification de la requête pour [{0}] avec JASPIC
persistentProviderRegistrations.deleteFail=Le fichier temporaire [{0}] n''a pas pu être effacé
persistentProviderRegistrations.existsDeleteFail=Le fichier temporaire [{0}] existe déjà et ne peut être effacé
persistentProviderRegistrations.moveFail=Echec de déplacement de [{0}] vers [{1}]
simpleServerAuthConfig.noModules=Aucun ServerAuthModules n'est configuré

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.load=[{0}]から永続的なプロバイダ登録を読み込みます。
authConfigFactoryImpl.registerClass=アプリケーションコンテキスト [{2}] のレイヤー [{1}] にクラス [{0}] を登録します。
authConfigFactoryImpl.registerInstance=レイヤ[{1}]とアプリケーションコンテキスト[{2}]のタイプ[{0}]のインスタンスの登録
authConfigFactoryImpl.zeroLengthAppContext=文字列長が 0 のアプリケーションコンテキスト名は不正です。
authConfigFactoryImpl.zeroLengthMessageLayer=長さゼロのメッセージ層名は無効です
callbackHandlerImpl.jaspicCallbackMissing=受信したタイプ[{0}]のサポートされていないJASPICコールバックが無視されました。
jaspicAuthenticator.authenticate=JASPIC経由で[{0}]へのリクエストを認証しています
persistentProviderRegistrations.deleteFail=一時ファイル [{0}] を削除できません。
persistentProviderRegistrations.existsDeleteFail=同名の一時ファイル [{0}] が存在し、削除もできませんでした。
persistentProviderRegistrations.moveFail=[{0}]を[{1}]に移動できませんでした。
simpleServerAuthConfig.noModules="ServerAuthModulesが設定されていません"

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.load=[{0}](으)로부터 persistent provider 등록 사항들을 로드합니다.
authConfigFactoryImpl.registerClass=레이어 [{1}]와(과) 애플리케이션 컨텍스트 [{2}]을(를) 위한 클래스 [{0}]을(를) 등록합니다.
authConfigFactoryImpl.registerInstance=레이어 [{1}]와(과) 애플리케이션 컨텍스트 [{2}]을(를) 위한 타입 [{0}]의 인스턴스를 등록합니다.
authConfigFactoryImpl.zeroLengthAppContext=애플리케이션 컨텍스트 이름의 길이가 0으로, 이는 유효하지 않습니다.
authConfigFactoryImpl.zeroLengthMessageLayer=길이가 0인 메시지 레이어 이름은 유효하지 않습니다.
callbackHandlerImpl.jaspicCallbackMissing=타입이 [{0}]인 지원되지 않는 JASPIC 콜백을 받았는데, 이는 무시됩니다.
jaspicAuthenticator.authenticate=[{0}]을(를) 위한 요청을 JASPIC를 통하여 인증합니다.
persistentProviderRegistrations.deleteFail=임시 파일 [{0}]을(를) 삭제할 수 없습니다.
persistentProviderRegistrations.existsDeleteFail=임시 파일 [{0}]이(가) 이미 존재하며 삭제될 수 없습니다.
persistentProviderRegistrations.moveFail=[{0}]을(를) [{1}](으)로 이동시키지 못했습니다.
simpleServerAuthConfig.noModules="ServerAuthModule이 설정되지 않음"

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
persistentProviderRegistrations.existsDeleteFail=Временный файл [{0}] уже существует и не может быть удалён

View File

@@ -0,0 +1,26 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
authConfigFactoryImpl.load=从[{0}]加载持久化提供者注册信息
authConfigFactoryImpl.zeroLengthAppContext=:)应用上下文名称的长度为0是无效的
authConfigFactoryImpl.zeroLengthMessageLayer=零长度的消息层名称是无效的
jaspicAuthenticator.authenticate=通过JASPIC验证[{0}]的请求
persistentProviderRegistrations.deleteFail=无法删除临时文件[{0}]
persistentProviderRegistrations.existsDeleteFail=临时文件[{0}]已存在且无法删除
persistentProviderRegistrations.moveFail=无法将[{0}]移至[{1}]
simpleServerAuthConfig.noModules=“没有配置ServerAuthModules”

View File

@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.message.MessageInfo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.res.StringManager;
public class MessageInfoImpl implements MessageInfo {
protected static final StringManager sm = StringManager.getManager(MessageInfoImpl.class);
public static final String IS_MANDATORY = "javax.security.auth.message.MessagePolicy.isMandatory";
private final Map<String, Object> map = new HashMap<>();
private HttpServletRequest request;
private HttpServletResponse response;
public MessageInfoImpl() {
}
public MessageInfoImpl(HttpServletRequest request, HttpServletResponse response, boolean authMandatory) {
this.request = request;
this.response = response;
map.put(IS_MANDATORY, Boolean.toString(authMandatory));
}
@Override
@SuppressWarnings("rawtypes")
// JASPIC uses raw types
public Map getMap() {
return map;
}
@Override
public Object getRequestMessage() {
return request;
}
@Override
public Object getResponseMessage() {
return response;
}
@Override
public void setRequestMessage(Object request) {
if (!(request instanceof HttpServletRequest)) {
throw new IllegalArgumentException(sm.getString("authenticator.jaspic.badRequestType",
request.getClass().getName()));
}
this.request = (HttpServletRequest) request;
}
@Override
public void setResponseMessage(Object response) {
if (!(response instanceof HttpServletResponse)) {
throw new IllegalArgumentException(sm.getString("authenticator.jaspic.badResponseType",
response.getClass().getName()));
}
this.response = (HttpServletResponse) response;
}
}

View File

@@ -0,0 +1,265 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.res.StringManager;
import org.xml.sax.SAXException;
/**
* Utility class for the loading and saving of JASPIC persistent provider
* registrations.
*/
final class PersistentProviderRegistrations {
private static final StringManager sm =
StringManager.getManager(PersistentProviderRegistrations.class);
private PersistentProviderRegistrations() {
// Utility class. Hide default constructor
}
static Providers loadProviders(File configFile) {
try (InputStream is = new FileInputStream(configFile)) {
// Construct a digester to read the XML input file
Digester digester = new Digester();
try {
digester.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
digester.setValidating(true);
digester.setNamespaceAware(true);
} catch (Exception e) {
throw new SecurityException(e);
}
// Create an object to hold the parse results and put it on the top
// of the digester's stack
Providers result = new Providers();
digester.push(result);
// Configure the digester
digester.addObjectCreate("jaspic-providers/provider", Provider.class.getName());
digester.addSetProperties("jaspic-providers/provider");
digester.addSetNext("jaspic-providers/provider", "addProvider", Provider.class.getName());
digester.addObjectCreate("jaspic-providers/provider/property", Property.class.getName());
digester.addSetProperties("jaspic-providers/provider/property");
digester.addSetNext("jaspic-providers/provider/property", "addProperty", Property.class.getName());
// Parse the input
digester.parse(is);
return result;
} catch (IOException | SAXException e) {
throw new SecurityException(e);
}
}
static void writeProviders(Providers providers, File configFile) {
File configFileOld = new File(configFile.getAbsolutePath() + ".old");
File configFileNew = new File(configFile.getAbsolutePath() + ".new");
// Remove left over temporary files if present
if (configFileOld.exists()) {
if (configFileOld.delete()) {
throw new SecurityException(sm.getString(
"persistentProviderRegistrations.existsDeleteFail",
configFileOld.getAbsolutePath()));
}
}
if (configFileNew.exists()) {
if (configFileNew.delete()) {
throw new SecurityException(sm.getString(
"persistentProviderRegistrations.existsDeleteFail",
configFileNew.getAbsolutePath()));
}
}
// Write out the providers to the temporary new file
try (OutputStream fos = new FileOutputStream(configFileNew);
Writer writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
writer.write(
"<?xml version='1.0' encoding='utf-8'?>\n" +
"<jaspic-providers\n" +
" xmlns=\"http://tomcat.apache.org/xml\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://tomcat.apache.org/xml jaspic-providers.xsd\"\n" +
" version=\"1.0\">\n");
for (Provider provider : providers.providers) {
writer.write(" <provider");
writeOptional("className", provider.getClassName(), writer);
writeOptional("layer", provider.getLayer(), writer);
writeOptional("appContext", provider.getAppContext(), writer);
writeOptional("description", provider.getDescription(), writer);
writer.write(">\n");
for (Entry<String,String> entry : provider.getProperties().entrySet()) {
writer.write(" <property name=\"");
writer.write(entry.getKey());
writer.write("\" value=\"");
writer.write(entry.getValue());
writer.write("\"/>\n");
}
writer.write(" </provider>\n");
}
writer.write("</jaspic-providers>\n");
} catch (IOException e) {
if (!configFileNew.delete()) {
Log log = LogFactory.getLog(PersistentProviderRegistrations.class);
log.warn(sm.getString("persistentProviderRegistrations.deleteFail",
configFileNew.getAbsolutePath()));
}
throw new SecurityException(e);
}
// Move the current file out of the way
if (configFile.isFile()) {
if (!configFile.renameTo(configFileOld)) {
throw new SecurityException(sm.getString("persistentProviderRegistrations.moveFail",
configFile.getAbsolutePath(), configFileOld.getAbsolutePath()));
}
}
// Move the new file into place
if (!configFileNew.renameTo(configFile)) {
throw new SecurityException(sm.getString("persistentProviderRegistrations.moveFail",
configFileNew.getAbsolutePath(), configFile.getAbsolutePath()));
}
// Remove the old file
if (configFileOld.exists() && !configFileOld.delete()) {
Log log = LogFactory.getLog(PersistentProviderRegistrations.class);
log.warn(sm.getString("persistentProviderRegistrations.deleteFail",
configFileOld.getAbsolutePath()));
}
}
private static void writeOptional(String name, String value, Writer writer) throws IOException {
if (value != null) {
writer.write(" " + name + "=\"");
writer.write(value);
writer.write("\"");
}
}
public static class Providers {
private final List<Provider> providers = new ArrayList<>();
public void addProvider(Provider provider) {
providers.add(provider);
}
public List<Provider> getProviders() {
return providers;
}
}
public static class Provider {
private String className;
private String layer;
private String appContext;
private String description;
private final Map<String,String> properties = new HashMap<>();
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getLayer() {
return layer;
}
public void setLayer(String layer) {
this.layer = layer;
}
public String getAppContext() {
return appContext;
}
public void setAppContext(String appContext) {
this.appContext = appContext;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void addProperty(Property property) {
properties.put(property.getName(), property.getValue());
}
void addProperty(String name, String value) {
properties.put(name, value);
}
public Map<String,String> getProperties() {
return properties;
}
}
public static class Property {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@@ -0,0 +1,89 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.config.AuthConfigFactory;
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.ClientAuthConfig;
import javax.security.auth.message.config.ServerAuthConfig;
/**
* Basic implementation primarily intended for use when using third-party
* {@link javax.security.auth.message.module.ServerAuthModule} implementations
* that only provide the module.
*/
public class SimpleAuthConfigProvider implements AuthConfigProvider {
private final Map<String,String> properties;
private volatile ServerAuthConfig serverAuthConfig;
public SimpleAuthConfigProvider(Map<String,String> properties, AuthConfigFactory factory) {
this.properties = properties;
if (factory != null) {
factory.registerConfigProvider(this, null, null, "Automatic registration");
}
}
/**
* {@inheritDoc}
* <p>
* This implementation does not support client-side authentication and
* therefore always returns {@code null}.
*/
@Override
public ClientAuthConfig getClientAuthConfig(String layer, String appContext,
CallbackHandler handler) throws AuthException {
return null;
}
@Override
public ServerAuthConfig getServerAuthConfig(String layer, String appContext,
CallbackHandler handler) throws AuthException {
ServerAuthConfig serverAuthConfig = this.serverAuthConfig;
if (serverAuthConfig == null) {
synchronized (this) {
if (this.serverAuthConfig == null) {
this.serverAuthConfig = createServerAuthConfig(layer, appContext, handler, properties);
}
serverAuthConfig = this.serverAuthConfig;
}
}
return serverAuthConfig;
}
protected ServerAuthConfig createServerAuthConfig(String layer, String appContext,
CallbackHandler handler, Map<String,String> properties) {
return new SimpleServerAuthConfig(layer, appContext, handler, properties);
}
@Override
public void refresh() {
ServerAuthConfig serverAuthConfig = this.serverAuthConfig;
if (serverAuthConfig != null) {
serverAuthConfig.refresh();
}
}
}

View File

@@ -0,0 +1,150 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.config.ServerAuthConfig;
import javax.security.auth.message.config.ServerAuthContext;
import javax.security.auth.message.module.ServerAuthModule;
import org.apache.tomcat.util.res.StringManager;
/**
* Basic implementation primarily intended for use when using third-party
* {@link ServerAuthModule} implementations that only provide the module. This
* implementation supports configuring the {@link ServerAuthContext} with
* multiple modules.
*/
public class SimpleServerAuthConfig implements ServerAuthConfig {
private static StringManager sm = StringManager.getManager(SimpleServerAuthConfig.class);
private static final String SERVER_AUTH_MODULE_KEY_PREFIX =
"org.apache.catalina.authenticator.jaspic.ServerAuthModule.";
private final String layer;
private final String appContext;
private final CallbackHandler handler;
private final Map<String,String> properties;
private volatile ServerAuthContext serverAuthContext;
public SimpleServerAuthConfig(String layer, String appContext, CallbackHandler handler,
Map<String,String> properties) {
this.layer = layer;
this.appContext = appContext;
this.handler = handler;
this.properties = properties;
}
@Override
public String getMessageLayer() {
return layer;
}
@Override
public String getAppContext() {
return appContext;
}
@Override
public String getAuthContextID(MessageInfo messageInfo) {
return messageInfo.toString();
}
@Override
public void refresh() {
serverAuthContext = null;
}
@Override
public boolean isProtected() {
return false;
}
@SuppressWarnings({"rawtypes", "unchecked"}) // JASPIC API uses raw types
@Override
public ServerAuthContext getAuthContext(String authContextID, Subject serviceSubject,
Map properties) throws AuthException {
ServerAuthContext serverAuthContext = this.serverAuthContext;
if (serverAuthContext == null) {
synchronized (this) {
if (this.serverAuthContext == null) {
Map<String,String> mergedProperties = new HashMap<>();
if (this.properties != null) {
mergedProperties.putAll(this.properties);
}
if (properties != null) {
mergedProperties.putAll(properties);
}
List<ServerAuthModule> modules = new ArrayList<>();
int moduleIndex = 1;
String key = SERVER_AUTH_MODULE_KEY_PREFIX + moduleIndex;
String moduleClassName = mergedProperties.get(key);
while (moduleClassName != null) {
try {
Class<?> clazz = Class.forName(moduleClassName);
ServerAuthModule module =
(ServerAuthModule) clazz.getConstructor().newInstance();
module.initialize(null, null, handler, mergedProperties);
modules.add(module);
} catch (ReflectiveOperationException | IllegalArgumentException |
SecurityException e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
// Look for the next module
moduleIndex++;
key = SERVER_AUTH_MODULE_KEY_PREFIX + moduleIndex;
moduleClassName = mergedProperties.get(key);
}
if (modules.size() == 0) {
throw new AuthException(sm.getString("simpleServerAuthConfig.noModules"));
}
this.serverAuthContext = createServerAuthContext(modules);
}
serverAuthContext = this.serverAuthContext;
}
}
return serverAuthContext;
}
protected ServerAuthContext createServerAuthContext(List<ServerAuthModule> modules) {
return new SimpleServerAuthContext(modules);
}
}

View File

@@ -0,0 +1,74 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.authenticator.jaspic;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.config.ServerAuthContext;
import javax.security.auth.message.module.ServerAuthModule;
/**
* Basic implementation primarily intended for use when using third-party
* {@link ServerAuthModule} implementations that only provide the module. This
* implementation supports multiple modules and will treat the user as
* authenticated if any one module is able to authenticate the user.
*/
public class SimpleServerAuthContext implements ServerAuthContext {
private final List<ServerAuthModule> modules;
public SimpleServerAuthContext(List<ServerAuthModule> modules) {
this.modules = modules;
}
@SuppressWarnings("unchecked") // JASPIC API uses raw types
@Override
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
Subject serviceSubject) throws AuthException {
for (int moduleIndex = 0; moduleIndex < modules.size(); moduleIndex++) {
ServerAuthModule module = modules.get(moduleIndex);
AuthStatus result = module.validateRequest(messageInfo, clientSubject, serviceSubject);
if (result != AuthStatus.SEND_FAILURE) {
messageInfo.getMap().put("moduleIndex", Integer.valueOf(moduleIndex));
return result;
}
}
return AuthStatus.SEND_FAILURE;
}
@Override
public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject)
throws AuthException {
ServerAuthModule module = modules.get(((Integer) messageInfo.getMap().get("moduleIndex")).intValue());
return module.secureResponse(messageInfo, serviceSubject);
}
@Override
public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException {
for (ServerAuthModule module : modules) {
module.cleanSubject(messageInfo, subject);
}
}
}