001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.jmxremoting;
017:
018: import java.util.Map;
019: import java.util.Collections;
020: import java.util.HashMap;
021: import javax.management.remote.JMXAuthenticator;
022: import javax.management.remote.JMXConnectionNotification;
023: import javax.management.NotificationListener;
024: import javax.management.Notification;
025: import javax.security.auth.Subject;
026: import javax.security.auth.login.LoginContext;
027: import javax.security.auth.login.LoginException;
028:
029: /**
030: * JMX Authenticator that checks the Credentials by logging in via JAAS.
031: *
032: * @version $Rev: 591213 $ $Date: 2007-11-01 20:46:17 -0700 (Thu, 01 Nov 2007) $
033: */
034: public class Authenticator implements JMXAuthenticator,
035: NotificationListener {
036: private final String configName;
037: private final ClassLoader cl;
038: private ThreadLocal<LoginContext> threadContext = new ThreadLocal<LoginContext>();
039: private Map<String, LoginContext> contextMap = Collections
040: .synchronizedMap(new HashMap<String, LoginContext>());
041:
042: /**
043: * Constructor indicating which JAAS Application Configuration Entry to use.
044: * @param configName the JAAS config name
045: * @param cl classloader to use as TCCL for operations
046: */
047: public Authenticator(String configName, ClassLoader cl) {
048: this .configName = configName;
049: this .cl = cl;
050: }
051:
052: public Subject authenticate(Object o) throws SecurityException {
053: if (!(o instanceof String[])) {
054: throw new IllegalArgumentException(
055: "Expected String[2], got "
056: + (o == null ? null : o.getClass()
057: .getName()));
058: }
059: String[] params = (String[]) o;
060: if (params.length != 2) {
061: throw new IllegalArgumentException(
062: "Expected String[2] but length was "
063: + params.length);
064: }
065:
066: Thread thread = Thread.currentThread();
067: ClassLoader oldCL = thread.getContextClassLoader();
068: Credentials credentials = new Credentials(params[0], params[1]);
069: try {
070: thread.setContextClassLoader(cl);
071: //TODO consider using ContextManager for login and checking a permission against the ACC
072: //to do e.g. deployments.
073: LoginContext context = new LoginContext(configName,
074: credentials);
075: context.login();
076: threadContext.set(context);
077: return context.getSubject();
078: } catch (LoginException e) {
079: // do not propogate cause - we don't know what information is may contain
080: throw new SecurityException("Invalid login");
081: } finally {
082: credentials.clear();
083: thread.setContextClassLoader(oldCL);
084: }
085: }
086:
087: public void handleNotification(Notification notification, Object o) {
088: if (notification instanceof JMXConnectionNotification) {
089: JMXConnectionNotification cxNotification = (JMXConnectionNotification) notification;
090: String type = cxNotification.getType();
091: String connectionId = cxNotification.getConnectionId();
092: if (JMXConnectionNotification.OPENED.equals(type)) {
093: LoginContext context = threadContext.get();
094: threadContext.set(null);
095: contextMap.put(connectionId, context);
096: } else {
097: LoginContext context = contextMap.remove(connectionId);
098: if (context != null) {
099: try {
100: context.logout();
101: } catch (LoginException e) {
102: //nothing we can do here...
103: }
104: }
105: }
106: }
107: }
108: }
|