1
17 package org.apache.catalina.authenticator.jaspic;
18
19 import java.io.File;
20 import java.lang.reflect.Constructor;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.CopyOnWriteArrayList;
29
30 import javax.security.auth.message.config.AuthConfigFactory;
31 import javax.security.auth.message.config.AuthConfigProvider;
32 import javax.security.auth.message.config.RegistrationListener;
33
34 import org.apache.catalina.Globals;
35 import org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Provider;
36 import org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations.Providers;
37 import org.apache.juli.logging.Log;
38 import org.apache.juli.logging.LogFactory;
39 import org.apache.tomcat.util.res.StringManager;
40
41 public class AuthConfigFactoryImpl extends AuthConfigFactory {
42
43 private final Log log = LogFactory.getLog(AuthConfigFactoryImpl.class);
44 private static final StringManager sm = StringManager.getManager(AuthConfigFactoryImpl.class);
45
46 private static final String CONFIG_PATH = "conf/jaspic-providers.xml";
47 private static final File CONFIG_FILE =
48 new File(System.getProperty(Globals.CATALINA_BASE_PROP), CONFIG_PATH);
49 private static final Object CONFIG_FILE_LOCK = new Object();
50
51 private static final String[] EMPTY_STRING_ARRAY = new String[0];
52
53 private static String DEFAULT_REGISTRATION_ID = getRegistrationID(null, null);
54
55 private final Map<String,RegistrationContextImpl> layerAppContextRegistrations =
56 new ConcurrentHashMap<>();
57 private final Map<String,RegistrationContextImpl> appContextRegistrations =
58 new ConcurrentHashMap<>();
59 private final Map<String,RegistrationContextImpl> layerRegistrations =
60 new ConcurrentHashMap<>();
61
62
63 private final Map<String,RegistrationContextImpl> defaultRegistration =
64 new ConcurrentHashMap<>(1);
65
66
67 public AuthConfigFactoryImpl() {
68 loadPersistentRegistrations();
69 }
70
71
72 @Override
73 public AuthConfigProvider getConfigProvider(String layer, String appContext,
74 RegistrationListener listener) {
75 RegistrationContextImpl registrationContext =
76 findRegistrationContextImpl(layer, appContext);
77 if (registrationContext != null) {
78 if (listener != null) {
79 RegistrationListenerWrapper wrapper = new RegistrationListenerWrapper(
80 layer, appContext, listener);
81 registrationContext.addListener(wrapper);
82 }
83 return registrationContext.getProvider();
84 }
85 return null;
86 }
87
88
89 @Override
90 public String registerConfigProvider(String className,
91 @SuppressWarnings("rawtypes") Map properties, String layer, String appContext,
92 String description) {
93 String registrationID =
94 doRegisterConfigProvider(className, properties, layer, appContext, description);
95 savePersistentRegistrations();
96 return registrationID;
97 }
98
99
100 @SuppressWarnings("unchecked")
101 private String doRegisterConfigProvider(String className,
102 @SuppressWarnings("rawtypes") Map properties, String layer, String appContext,
103 String description) {
104 if (log.isDebugEnabled()) {
105 log.debug(sm.getString("authConfigFactoryImpl.registerClass",
106 className, layer, appContext));
107 }
108
109 AuthConfigProvider provider = null;
110 if (className != null) {
111 provider = createAuthConfigProvider(className, properties);
112 }
113
114 String registrationID = getRegistrationID(layer, appContext);
115 RegistrationContextImpl registrationContextImpl = new RegistrationContextImpl(
116 layer, appContext, description, true, provider, properties);
117 addRegistrationContextImpl(layer, appContext, registrationID, registrationContextImpl);
118 return registrationID;
119 }
120
121
122 private AuthConfigProvider createAuthConfigProvider(String className,
123 @SuppressWarnings("rawtypes") Map properties) throws SecurityException {
124 Class<?> clazz = null;
125 AuthConfigProvider provider = null;
126 try {
127 clazz = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
128 } catch (ClassNotFoundException e) {
129
130 }
131 try {
132 if (clazz == null) {
133 clazz = Class.forName(className);
134 }
135 Constructor<?> constructor = clazz.getConstructor(Map.class, AuthConfigFactory.class);
136 provider = (AuthConfigProvider) constructor.newInstance(properties, null);
137 } catch (ReflectiveOperationException | IllegalArgumentException e) {
138 throw new SecurityException(e);
139 }
140 return provider;
141 }
142
143
144 @Override
145 public String registerConfigProvider(AuthConfigProvider provider, String layer,
146 String appContext, String description) {
147 if (log.isDebugEnabled()) {
148 log.debug(sm.getString("authConfigFactoryImpl.registerInstance",
149 provider.getClass().getName(), layer, appContext));
150 }
151 String registrationID = getRegistrationID(layer, appContext);
152 RegistrationContextImpl registrationContextImpl = new RegistrationContextImpl(
153 layer, appContext, description, false, provider, null);
154 addRegistrationContextImpl(layer, appContext, registrationID, registrationContextImpl);
155 return registrationID;
156 }
157
158
159 private void addRegistrationContextImpl(String layer, String appContext,
160 String registrationID, RegistrationContextImpl registrationContextImpl) {
161 RegistrationContextImpl previous = null;
162
163
164 if (layer != null && appContext != null) {
165 previous = layerAppContextRegistrations.put(registrationID, registrationContextImpl);
166 } else if (layer == null && appContext != null) {
167 previous = appContextRegistrations.put(registrationID, registrationContextImpl);
168 } else if (layer != null && appContext == null) {
169 previous = layerRegistrations.put(registrationID, registrationContextImpl);
170 } else {
171 previous = defaultRegistration.put(registrationID, registrationContextImpl);
172 }
173
174 if (previous == null) {
175
176
177
178
179 if (layer != null && appContext != null) {
180
181
182
183 RegistrationContextImpl registration =
184 appContextRegistrations.get(getRegistrationID(null, appContext));
185 if (registration != null) {
186 for (RegistrationListenerWrapper wrapper : registration.listeners) {
187 if (layer.equals(wrapper.getMessageLayer()) &&
188 appContext.equals(wrapper.getAppContext())) {
189 registration.listeners.remove(wrapper);
190 wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
191 }
192 }
193 }
194 }
195 if (appContext != null) {
196
197
198
199 for (RegistrationContextImpl registration : layerRegistrations.values()) {
200 for (RegistrationListenerWrapper wrapper : registration.listeners) {
201 if (appContext.equals(wrapper.getAppContext())) {
202 registration.listeners.remove(wrapper);
203 wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
204 }
205 }
206 }
207 }
208 if (layer != null || appContext != null) {
209
210 for (RegistrationContextImpl registration : defaultRegistration.values()) {
211 for (RegistrationListenerWrapper wrapper : registration.listeners) {
212 if (appContext != null && appContext.equals(wrapper.getAppContext()) ||
213 layer != null && layer.equals(wrapper.getMessageLayer())) {
214 registration.listeners.remove(wrapper);
215 wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
216 }
217 }
218 }
219 }
220 } else {
221
222 for (RegistrationListenerWrapper wrapper : previous.listeners) {
223 previous.listeners.remove(wrapper);
224 wrapper.listener.notify(wrapper.messageLayer, wrapper.appContext);
225 }
226 }
227 }
228
229
230 @Override
231 public boolean removeRegistration(String registrationID) {
232 RegistrationContextImpl registration = null;
233 if (DEFAULT_REGISTRATION_ID.equals(registrationID)) {
234 registration = defaultRegistration.remove(registrationID);
235 }
236 if (registration == null) {
237 registration = layerAppContextRegistrations.remove(registrationID);
238 }
239 if (registration == null) {
240 registration = appContextRegistrations.remove(registrationID);
241 }
242 if (registration == null) {
243 registration = layerRegistrations.remove(registrationID);
244 }
245
246 if (registration == null) {
247 return false;
248 } else {
249 for (RegistrationListenerWrapper wrapper : registration.listeners) {
250 wrapper.getListener().notify(wrapper.getMessageLayer(), wrapper.getAppContext());
251 }
252 if (registration.isPersistent()) {
253 savePersistentRegistrations();
254 }
255 return true;
256 }
257 }
258
259
260 @Override
261 public String[] detachListener(RegistrationListener listener, String layer, String appContext) {
262 String registrationID = getRegistrationID(layer, appContext);
263 RegistrationContextImpl registrationContext = findRegistrationContextImpl(layer, appContext);
264 if (registrationContext != null && registrationContext.removeListener(listener)) {
265 return new String[] { registrationID };
266 }
267 return EMPTY_STRING_ARRAY;
268 }
269
270
271 @Override
272 public String[] getRegistrationIDs(AuthConfigProvider provider) {
273 List<String> result = new ArrayList<>();
274 if (provider == null) {
275 result.addAll(layerAppContextRegistrations.keySet());
276 result.addAll(appContextRegistrations.keySet());
277 result.addAll(layerRegistrations.keySet());
278 if (!defaultRegistration.isEmpty()) {
279 result.add(DEFAULT_REGISTRATION_ID);
280 }
281 } else {
282 findProvider(provider, layerAppContextRegistrations, result);
283 findProvider(provider, appContextRegistrations, result);
284 findProvider(provider, layerRegistrations, result);
285 findProvider(provider, defaultRegistration, result);
286 }
287 return result.toArray(EMPTY_STRING_ARRAY);
288 }
289
290
291 private void findProvider(AuthConfigProvider provider,
292 Map<String,RegistrationContextImpl> registrations, List<String> result) {
293 for (Entry<String,RegistrationContextImpl> entry : registrations.entrySet()) {
294 if (provider.equals(entry.getValue().getProvider())) {
295 result.add(entry.getKey());
296 }
297 }
298 }
299
300
301 @Override
302 public RegistrationContext getRegistrationContext(String registrationID) {
303 RegistrationContext result = defaultRegistration.get(registrationID);
304 if (result == null) {
305 result = layerAppContextRegistrations.get(registrationID);
306 }
307 if (result == null) {
308 result = appContextRegistrations.get(registrationID);
309 }
310 if (result == null) {
311 result = layerRegistrations.get(registrationID);
312 }
313 return result;
314 }
315
316
317 @Override
318 public void refresh() {
319 loadPersistentRegistrations();
320 }
321
322
323 private static String getRegistrationID(String layer, String appContext) {
324 if (layer != null && layer.length() == 0) {
325 throw new IllegalArgumentException(
326 sm.getString("authConfigFactoryImpl.zeroLengthMessageLayer"));
327 }
328 if (appContext != null && appContext.length() == 0) {
329 throw new IllegalArgumentException(
330 sm.getString("authConfigFactoryImpl.zeroLengthAppContext"));
331 }
332 return (layer == null ? "" : layer) + ":" + (appContext == null ? "" : appContext);
333 }
334
335
336 private void loadPersistentRegistrations() {
337 synchronized (CONFIG_FILE_LOCK) {
338 if (log.isDebugEnabled()) {
339 log.debug(sm.getString("authConfigFactoryImpl.load",
340 CONFIG_FILE.getAbsolutePath()));
341 }
342 if (!CONFIG_FILE.isFile()) {
343 return;
344 }
345 Providers providers = PersistentProviderRegistrations.loadProviders(CONFIG_FILE);
346 for (Provider provider : providers.getProviders()) {
347 doRegisterConfigProvider(provider.getClassName(), provider.getProperties(),
348 provider.getLayer(), provider.getAppContext(), provider.getDescription());
349 }
350 }
351 }
352
353
354 private void savePersistentRegistrations() {
355 synchronized (CONFIG_FILE_LOCK) {
356 Providers providers = new Providers();
357 savePersistentProviders(providers, layerAppContextRegistrations);
358 savePersistentProviders(providers, appContextRegistrations);
359 savePersistentProviders(providers, layerRegistrations);
360 savePersistentProviders(providers, defaultRegistration);
361 PersistentProviderRegistrations.writeProviders(providers, CONFIG_FILE);
362 }
363 }
364
365
366 private void savePersistentProviders(Providers providers,
367 Map<String,RegistrationContextImpl> registrations) {
368 for (Entry<String,RegistrationContextImpl> entry : registrations.entrySet()) {
369 savePersistentProvider(providers, entry.getValue());
370 }
371 }
372
373
374 private void savePersistentProvider(Providers providers,
375 RegistrationContextImpl registrationContextImpl) {
376 if (registrationContextImpl != null && registrationContextImpl.isPersistent()) {
377 Provider provider = new Provider();
378 provider.setAppContext(registrationContextImpl.getAppContext());
379 if (registrationContextImpl.getProvider() != null) {
380 provider.setClassName(registrationContextImpl.getProvider().getClass().getName());
381 }
382 provider.setDescription(registrationContextImpl.getDescription());
383 provider.setLayer(registrationContextImpl.getMessageLayer());
384 for (Entry<String,String> property : registrationContextImpl.getProperties().entrySet()) {
385 provider.addProperty(property.getKey(), property.getValue());
386 }
387 providers.addProvider(provider);
388 }
389 }
390
391
392 private RegistrationContextImpl findRegistrationContextImpl(String layer, String appContext) {
393 RegistrationContextImpl result;
394 result = layerAppContextRegistrations.get(getRegistrationID(layer, appContext));
395 if (result == null) {
396 result = appContextRegistrations.get(getRegistrationID(null, appContext));
397 }
398 if (result == null) {
399 result = layerRegistrations.get(getRegistrationID(layer, null));
400 }
401 if (result == null) {
402 result = defaultRegistration.get(DEFAULT_REGISTRATION_ID);
403 }
404 return result;
405 }
406
407
408 private static class RegistrationContextImpl implements RegistrationContext {
409
410 private RegistrationContextImpl(String messageLayer, String appContext, String description,
411 boolean persistent, AuthConfigProvider provider, Map<String,String> properties) {
412 this.messageLayer = messageLayer;
413 this.appContext = appContext;
414 this.description = description;
415 this.persistent = persistent;
416 this.provider = provider;
417 Map<String,String> propertiesCopy = new HashMap<>();
418 if (properties != null) {
419 propertiesCopy.putAll(properties);
420 }
421 this.properties = Collections.unmodifiableMap(propertiesCopy);
422 }
423
424 private final String messageLayer;
425 private final String appContext;
426 private final String description;
427 private final boolean persistent;
428 private final AuthConfigProvider provider;
429 private final Map<String,String> properties;
430 private final List<RegistrationListenerWrapper> listeners = new CopyOnWriteArrayList<>();
431
432 @Override
433 public String getMessageLayer() {
434 return messageLayer;
435 }
436
437
438 @Override
439 public String getAppContext() {
440 return appContext;
441 }
442
443 @Override
444 public String getDescription() {
445 return description;
446 }
447
448
449 @Override
450 public boolean isPersistent() {
451 return persistent;
452 }
453
454
455 private AuthConfigProvider getProvider() {
456 return provider;
457 }
458
459
460 private void addListener(RegistrationListenerWrapper listener) {
461 if (listener != null) {
462 listeners.add(listener);
463 }
464 }
465
466
467 private Map<String,String> getProperties() {
468 return properties;
469 }
470
471
472 private boolean removeListener(RegistrationListener listener) {
473 boolean result = false;
474 for (RegistrationListenerWrapper wrapper : listeners) {
475 if (wrapper.getListener().equals(listener)) {
476 listeners.remove(wrapper);
477 result = true;
478 }
479 }
480 return result;
481 }
482 }
483
484
485 private static class RegistrationListenerWrapper {
486
487 private final String messageLayer;
488 private final String appContext;
489 private final RegistrationListener listener;
490
491
492 public RegistrationListenerWrapper(String messageLayer, String appContext,
493 RegistrationListener listener) {
494 this.messageLayer = messageLayer;
495 this.appContext = appContext;
496 this.listener = listener;
497 }
498
499
500 public String getMessageLayer() {
501 return messageLayer;
502 }
503
504
505 public String getAppContext() {
506 return appContext;
507 }
508
509
510 public RegistrationListener getListener() {
511 return listener;
512 }
513 }
514 }
515