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    }