init
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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é
|
||||
@@ -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が設定されていません"
|
||||
@@ -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이 설정되지 않음"
|
||||
@@ -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}] уже существует и не может быть удалён
|
||||
@@ -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”
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user