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.jaas;
022    
023    import java.security.Principal;
024    import java.util.Arrays;
025    import java.util.Collections;
026    import java.util.HashSet;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Set;
030    
031    import javax.security.auth.Subject;
032    import javax.security.auth.callback.CallbackHandler;
033    import javax.security.auth.login.LoginException;
034    import javax.security.auth.spi.LoginModule;
035    
036    import org.apache.geronimo.security.DomainPrincipal;
037    import org.apache.geronimo.security.RealmPrincipal;
038    
039    /**
040     * @version $Revision: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
041     */
042    public class WrappingLoginModule implements LoginModule {
043        public static final String CLASS_OPTION = WrappingLoginModule.class.getName() + ".LoginModuleClass";
044        public static final String DOMAIN_OPTION = WrappingLoginModule.class.getName() + ".DomainName";
045        public static final String REALM_OPTION = WrappingLoginModule.class.getName() + ".RealmName";
046        public static final List<String> supportedOptions = Collections.unmodifiableList(Arrays.asList(CLASS_OPTION, DOMAIN_OPTION, REALM_OPTION));
047        private String loginDomainName;
048        private String realmName;
049        private final Subject localSubject = new Subject();
050        private Subject subject;
051        private LoginModule delegate;
052        private final Set<Principal> wrapped = new HashSet<Principal>();
053    
054    
055        public WrappingLoginModule() {
056        }
057    
058        public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
059            this.subject = subject;
060            Class lmClass = (Class) options.get(CLASS_OPTION);
061            try {
062                delegate = (LoginModule) lmClass.newInstance();
063            } catch (Exception e) {
064                throw new RuntimeException("Could not create login module instance", e);
065            }
066            delegate.initialize(localSubject, callbackHandler, sharedState, options);
067            loginDomainName = (String) options.get(DOMAIN_OPTION);
068            realmName = (String) options.get(REALM_OPTION);
069        }
070    
071        public boolean login() throws LoginException {
072            return delegate.login();
073        }
074    
075        public boolean abort() throws LoginException {
076            return delegate.abort();
077        }
078    
079        public boolean commit() throws LoginException {
080            boolean result = delegate.commit();
081    
082            for (Principal principal: localSubject.getPrincipals()) {
083                wrapped.add(new DomainPrincipal(loginDomainName, principal));
084                wrapped.add(new RealmPrincipal(realmName, loginDomainName, principal));
085            }
086            subject.getPrincipals().addAll(wrapped);
087            subject.getPrincipals().addAll(localSubject.getPrincipals());
088            subject.getPrivateCredentials().addAll(localSubject.getPrivateCredentials());
089            subject.getPublicCredentials().addAll(localSubject.getPublicCredentials());
090            return result;
091        }
092    
093        public boolean logout() throws LoginException {
094            if(!subject.isReadOnly()) {
095                subject.getPrincipals().removeAll(wrapped);
096                subject.getPrincipals().removeAll(localSubject.getPrincipals());
097                subject.getPrivateCredentials().removeAll(localSubject.getPrivateCredentials());
098                subject.getPublicCredentials().removeAll(localSubject.getPublicCredentials());
099                wrapped.clear();
100            } else {
101                wrapped.clear();
102                localSubject.getPrincipals().clear();
103                localSubject.setReadOnly(); // This will ensure that credentails are destroyed by the delegate's logout method
104            }
105            
106            return delegate.logout();
107        }
108    }