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: 565912 $ $Date: 2007-08-14 17:03:11 -0400 (Tue, 14 Aug 2007) $ 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 }