001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020
021 package org.apache.geronimo.security.credentialstore;
022
023 import java.util.HashMap;
024 import java.util.Map;
025 import java.lang.reflect.Constructor;
026
027 import javax.security.auth.Subject;
028 import javax.security.auth.callback.Callback;
029 import javax.security.auth.callback.CallbackHandler;
030 import javax.security.auth.callback.UnsupportedCallbackException;
031 import javax.security.auth.login.LoginContext;
032 import javax.security.auth.login.LoginException;
033
034 import org.apache.geronimo.gbean.GBeanInfo;
035 import org.apache.geronimo.gbean.GBeanInfoBuilder;
036 import org.apache.geronimo.security.ContextManager;
037
038 /**
039 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
040 */
041 public class SimpleCredentialStoreImpl implements CredentialStore {
042
043 private final Map<String, Map<String, Map<String, SingleCallbackHandler>>> credentialStore = new HashMap<String, Map<String, Map<String, SingleCallbackHandler>>>();
044
045 public SimpleCredentialStoreImpl(Map<String, Map<String, Map<String, String>>> credentials, ClassLoader cl) {
046 if (credentials != null) {
047 for (Map.Entry<String, Map<String, Map<String, String>>> realmData: credentials.entrySet()) {
048 String realmName = realmData.getKey();
049 Map<String, Map<String, SingleCallbackHandler>> realm = getRealm(realmName);
050 for (Map.Entry<String, Map<String, String>> subjectData: realmData.getValue().entrySet()) {
051 String subjectId = subjectData.getKey();
052 Map<String, SingleCallbackHandler> subject = getSubject(realm, subjectId);
053 for (Map.Entry<String, String> credentialData: subjectData.getValue().entrySet()) {
054 String handlerType = credentialData.getKey();
055 String value = credentialData.getValue();
056 try {
057 Class<? extends SingleCallbackHandler> clazz = (Class<? extends SingleCallbackHandler>) cl.loadClass(handlerType);
058 Constructor<? extends SingleCallbackHandler> c = clazz.getConstructor(String.class);
059 SingleCallbackHandler handler = c.newInstance(value);
060 String callbackType = handler.getCallbackType();
061 subject.put(callbackType, handler);
062 } catch (Exception e) {
063 throw new IllegalArgumentException("Could not construct SingleCallbackHandler of type: " + handlerType + " and value: " + value + " for subjectId: " + subjectId + " and realm: " + realmName, e);
064 }
065 }
066 }
067
068 }
069 }
070 }
071
072 public Subject getSubject(String realm, String id) throws LoginException {
073 Map<String, Map<String, SingleCallbackHandler>> idMap = credentialStore.get(realm);
074 if (idMap == null) {
075 throw new LoginException("Unknown realm: " + realm);
076 }
077 final Map<String, SingleCallbackHandler> callbackInfos = idMap.get(id);
078 if (callbackInfos == null) {
079 throw new LoginException("Unknown id: " + id + " in realm: " + realm);
080 }
081 LoginContext loginContext = ContextManager.login(realm, new CallbackHandler() {
082
083 public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
084 for (Callback callback: callbacks) {
085 if (!callbackInfos.containsKey(callback.getClass().getName())) {
086 throw new UnsupportedCallbackException(callback);
087 }
088 SingleCallbackHandler singleCallbackHandler = callbackInfos.get(callback.getClass().getName());
089 singleCallbackHandler.handle(callback);
090 }
091 }
092 });
093 return loginContext.getSubject();
094 }
095
096 public void addEntry(String realm, String id, Map<String, SingleCallbackHandler> callbackInfos) {
097 Map<String, Map<String, SingleCallbackHandler>> idMap = getRealm(realm);
098 idMap.put(id, callbackInfos);
099 }
100
101 private Map<String, Map<String, SingleCallbackHandler>> getRealm(String realm) {
102 Map<String, Map<String, SingleCallbackHandler>> idMap = credentialStore.get(realm);
103 if (idMap == null) {
104 idMap = new HashMap<String, Map<String, SingleCallbackHandler>>();
105 credentialStore.put(realm, idMap);
106 }
107 return idMap;
108 }
109
110 private Map<String, SingleCallbackHandler> getSubject(Map<String, Map<String, SingleCallbackHandler>> realm, String subjectId) {
111 Map<String, SingleCallbackHandler> subject = realm.get(subjectId);
112 if (subject == null) {
113 subject = new HashMap<String, SingleCallbackHandler>();
114 realm.put(subjectId, subject);
115 }
116 return subject;
117 }
118
119 public static final GBeanInfo GBEAN_INFO;
120
121 static {
122 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(SimpleCredentialStoreImpl.class);
123
124 infoBuilder.addAttribute("credentialStore", Map.class, true);
125 infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
126
127 infoBuilder.setConstructor(new String[]{"credentialStore", "classLoader"});
128
129 GBEAN_INFO = infoBuilder.getBeanInfo();
130 }
131
132 public static GBeanInfo getGBeanInfo() {
133 return GBEAN_INFO;
134 }
135 }