001 /* 002 * Copyright 2010 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package com.hs.mail.security.login; 017 018 import java.io.BufferedInputStream; 019 import java.io.File; 020 import java.io.FileInputStream; 021 import java.io.IOException; 022 import java.security.Principal; 023 import java.util.Map; 024 import java.util.StringTokenizer; 025 026 import javax.security.auth.Subject; 027 import javax.security.auth.callback.Callback; 028 import javax.security.auth.callback.CallbackHandler; 029 import javax.security.auth.callback.NameCallback; 030 import javax.security.auth.callback.PasswordCallback; 031 import javax.security.auth.login.AccountNotFoundException; 032 import javax.security.auth.login.CredentialException; 033 import javax.security.auth.login.FailedLoginException; 034 import javax.security.auth.login.LoginException; 035 036 import org.apache.commons.io.IOUtils; 037 038 import com.hs.mail.io.LineReader; 039 import com.hs.mail.security.RolePrincipal; 040 import com.hs.mail.security.UserPrincipal; 041 042 /** 043 * A LoginModule that allows for authentication based on properties file. 044 * 045 * @author Won Chul Doh 046 * @since Aug 5, 2010 047 * 048 */ 049 public class PropertiesLoginModule extends BasicLoginModule { 050 051 private File file; 052 053 @Override 054 public void initialize(Subject subject, CallbackHandler callbackHandler, 055 Map<String, ?> sharedState, Map<String, ?> options) { 056 super.initialize(subject, callbackHandler, sharedState, options); 057 058 File baseDir = null; 059 if (System.getProperty("java.security.auth.login.config") != null) { 060 baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile(); 061 } else { 062 baseDir = new File("."); 063 } 064 065 String filename = getOption("file", null); 066 if (filename == null) 067 throw new RuntimeException("No file specified"); 068 file = new File(baseDir, filename); 069 } 070 071 @Override 072 protected Principal[] validate(Callback[] callbacks) throws LoginException { 073 String username = ((NameCallback) callbacks[0]).getName(); 074 char[] password = ((PasswordCallback) callbacks[1]).getPassword(); 075 076 String entry = getLine(file, username + "="); 077 if (entry == null) 078 throw new AccountNotFoundException("Account for " + username 079 + " not found"); 080 int index = entry.indexOf('='); 081 if (index == -1) 082 throw new FailedLoginException("Invalid user record"); 083 entry = entry.substring(index + 1); 084 index = entry.indexOf(':'); 085 if (index == -1) 086 throw new FailedLoginException("Invalid user record"); 087 String encodedPwd = entry.substring(0, index); 088 String roles = entry.substring(index + 1); 089 StringTokenizer st = new StringTokenizer(roles, ","); 090 Principal[] principals = new Principal[st.countTokens() + 1]; 091 for (int i = 0; i < principals.length -1; i++) { 092 principals[i] = new RolePrincipal(st.nextToken().trim()); 093 } 094 principals[principals.length - 1] = new UserPrincipal(username); 095 boolean ok = checkPassword(encodedPwd, password); 096 if (!ok) 097 throw new CredentialException("Incorrect password for " + username); 098 else 099 return principals; 100 } 101 102 private String getLine(File file, String start) throws LoginException { 103 LineReader reader = null; 104 BufferedInputStream is = null; 105 try { 106 is = new BufferedInputStream(new FileInputStream(file)); 107 reader = new LineReader(is); 108 int len = start.length(); 109 String line = null; 110 while ((line = reader.readLine()) != null) { 111 line = line.trim(); 112 if (!line.startsWith("#") 113 && line.regionMatches(false, 0, start, 0, len)) { 114 return line; 115 } 116 } 117 return null; 118 } catch (IOException e) { 119 throw new LoginException("Error while reading file: " + file); 120 } finally { 121 IOUtils.closeQuietly(is); 122 IOUtils.closeQuietly(reader); 123 } 124 } 125 126 }