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.realm.providers;
022
023 import java.io.InputStream;
024 import java.net.URI;
025 import java.util.HashSet;
026 import java.util.Map;
027 import java.util.Properties;
028 import java.util.Set;
029 import java.util.regex.Matcher;
030 import java.util.regex.Pattern;
031
032 import javax.security.auth.Subject;
033 import javax.security.auth.callback.Callback;
034 import javax.security.auth.callback.CallbackHandler;
035 import javax.security.auth.callback.NameCallback;
036 import javax.security.auth.callback.UnsupportedCallbackException;
037 import javax.security.auth.login.LoginException;
038 import javax.security.auth.spi.LoginModule;
039
040 import org.apache.commons.logging.Log;
041 import org.apache.commons.logging.LogFactory;
042 import org.apache.geronimo.common.GeronimoSecurityException;
043 import org.apache.geronimo.security.jaas.JaasLoginModuleUse;
044 import org.apache.geronimo.security.jaas.NamedUsernamePasswordCredential;
045 import org.apache.geronimo.system.serverinfo.ServerInfo;
046
047 /**
048 * GeronimoPropertiesFileMappedPasswordCredentialLoginModule adds NamedUsernamePasswordCredentials to the Subject.
049 * The NamedUsernamePasswordCredential are specified in a properties file specified in the options. Each line of the
050 * properties file is of the form:
051 *
052 * username=credentials
053 *
054 * where credentials is a comma-separated list of credentials and a credential is of the form
055 * name:username=password
056 *
057 * Thus a typical line would be:
058 *
059 * whee=foo:bar=baz,foo2:bar2=baz2
060 *
061 * This login module does not check credentials so it should never be able to cause a login to succeed.
062 * Therefore the lifecycle methods must return false to indicate success or throw a LoginException to indicate failure.
063 *
064 * @version $Rev: 565912 $ $Date: 2007-08-14 17:03:11 -0400 (Tue, 14 Aug 2007) $
065 */
066 public class GeronimoPropertiesFileMappedPasswordCredentialLoginModule implements LoginModule {
067
068 private static final Log log = LogFactory.getLog(GeronimoPropertiesFileMappedPasswordCredentialLoginModule.class);
069 public final static String CREDENTIALS_URI = "credentialsURI";
070 private final static Pattern pattern = Pattern.compile("([^:,=]*):([^:,=]*)=([^:,=]*)");
071
072 private final Set<NamedUsernamePasswordCredential> passwordCredentials = new HashSet<NamedUsernamePasswordCredential>();
073 private final Properties credentials = new Properties();
074
075 private Subject subject;
076 private CallbackHandler callbackHandler;
077
078 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
079 this.subject = subject;
080 this.callbackHandler = callbackHandler;
081 try {
082 ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
083 final String credentials = (String) options.get(CREDENTIALS_URI);
084 if (credentials == null) {
085 throw new IllegalArgumentException(CREDENTIALS_URI + " must be provided!");
086 }
087 URI usersURI = new URI(credentials);
088 loadProperties(serverInfo, usersURI);
089 } catch (Exception e) {
090 log.error("Initialization failed", e);
091 throw new IllegalArgumentException("Unable to configure properties file login module: " + e.getMessage(), e);
092 }
093 }
094
095 private void loadProperties(ServerInfo serverInfo, URI credentialsURI) throws GeronimoSecurityException {
096 try {
097 URI userFile = serverInfo.resolveServer(credentialsURI);
098 InputStream stream = userFile.toURL().openStream();
099 credentials.load(stream);
100 stream.close();
101 } catch (Exception e) {
102 log.error("Properties File Login Module - data load failed", e);
103 throw new GeronimoSecurityException(e);
104 }
105 }
106
107 public boolean login() throws LoginException {
108 Callback[] callbacks = new Callback[1];
109 callbacks[0] = new NameCallback("User name");
110 try {
111 callbackHandler.handle(callbacks);
112 } catch (java.io.IOException e) {
113 throw (LoginException) new LoginException("Unlikely IOException").initCause(e);
114 } catch (UnsupportedCallbackException e) {
115 throw (LoginException) new LoginException("Unlikely UnsupportedCallbackException").initCause(e);
116 }
117 String userName = ((NameCallback) callbacks[0]).getName();
118 String unparsedCredentials = credentials.getProperty(userName);
119 if (unparsedCredentials != null) {
120 parseCredentials(unparsedCredentials, passwordCredentials);
121 }
122 return false;
123 }
124
125 void parseCredentials(String unparsedCredentials, Set<NamedUsernamePasswordCredential> passwordCredentials) {
126 Matcher matcher = pattern.matcher(unparsedCredentials);
127 while (matcher.find()) {
128 String credentialName = matcher.group(1);
129 String credentialUser = matcher.group(2);
130 String credentialPassword = matcher.group(3);
131 NamedUsernamePasswordCredential credential = new NamedUsernamePasswordCredential(credentialUser, credentialPassword.toCharArray(), credentialName);
132 passwordCredentials.add(credential);
133 }
134 }
135
136 public boolean commit() throws LoginException {
137 subject.getPrivateCredentials().addAll(passwordCredentials);
138 return false;
139 }
140
141 public boolean abort() throws LoginException {
142 passwordCredentials.clear();
143 return false;
144 }
145
146 public boolean logout() throws LoginException {
147 passwordCredentials.clear();
148 return false;
149 }
150 }