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 }