View Javadoc

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) { //work around initial "fake" login
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 }