1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.security.realm.providers;
18
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.nio.channels.FileChannel;
24 import java.nio.channels.FileLock;
25 import java.text.DateFormat;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
28 import java.util.Map;
29 import javax.security.auth.Subject;
30 import javax.security.auth.callback.Callback;
31 import javax.security.auth.callback.CallbackHandler;
32 import javax.security.auth.callback.NameCallback;
33 import javax.security.auth.login.LoginException;
34 import javax.security.auth.spi.LoginModule;
35
36 import org.apache.geronimo.security.jaas.JaasLoginModuleUse;
37 import org.apache.geronimo.system.serverinfo.ServerInfo;
38
39 /**
40 * Writes audit records to a file for all authentication activity. Currently
41 * doesn't perform too well; perhaps the file management should be centralized
42 * and the IO objects kept open across many requests. It would also be nice
43 * to write in a more convenient XML format.
44 *
45 * This module does not write any Principals into the Subject.
46 *
47 * To enable this login module, set your primary login module to REQUIRED or
48 * OPTIONAL, and list this module after it (with any setting).
49 *
50 * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
51 */
52 public class FileAuditLoginModule implements LoginModule {
53 public static final String LOG_FILE_OPTION = "file";
54 private final static DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
55 private File logFile;
56 private CallbackHandler handler;
57 private String username;
58
59 public void initialize(Subject subject, CallbackHandler callbackHandler,
60 Map sharedState, Map options) {
61 String name = (String) options.get(LOG_FILE_OPTION);
62 ServerInfo info = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
63 logFile = info.resolve(name);
64 handler = callbackHandler;
65 }
66
67 public boolean login() throws LoginException {
68 NameCallback user = new NameCallback("User name:");
69 Callback[] callbacks = new Callback[]{user};
70 try {
71 handler.handle(callbacks);
72 } catch (Exception e) {
73 throw new LoginException("Unable to process callback: "+e);
74 }
75 if(callbacks.length != 1) {
76 throw new IllegalStateException("Number of callbacks changed by server!");
77 }
78 user = (NameCallback) callbacks[0];
79 username = user.getName();
80 writeToFile("Authentication attempt");
81
82 return true;
83 }
84
85 private synchronized void writeToFile(String action) {
86 Date date = new Date();
87 try {
88 FileOutputStream out = new FileOutputStream(logFile, true);
89 FileChannel channel = out.getChannel();
90 FileLock lock = channel.lock(0, Long.MAX_VALUE, false);
91 PrintWriter writer = new PrintWriter(out, false);
92 writer.println(DATE_FORMAT.format(date)+" - "+action+" - "+username);
93 writer.flush();
94 writer.close();
95 if(lock.isValid()) {
96 lock.release();
97 }
98 } catch (IOException e) {
99 throw new RuntimeException("Unable to write to authentication log file", e);
100 }
101 }
102
103 public boolean commit() throws LoginException {
104 writeToFile("Authentication succeeded");
105 return true;
106 }
107
108 public boolean abort() throws LoginException {
109 if(username != null) {
110 writeToFile("Authentication failed");
111 username = null;
112 }
113 return true;
114 }
115
116 public boolean logout() throws LoginException {
117 writeToFile("Explicit logout");
118 username = null;
119 return true;
120 }
121 }