1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.providers.jaas;
17
18 import org.acegisecurity.Authentication;
19 import org.acegisecurity.context.SecurityContextHolder;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 import java.util.Map;
25
26 import javax.security.auth.Subject;
27 import javax.security.auth.callback.CallbackHandler;
28 import javax.security.auth.login.LoginException;
29 import javax.security.auth.spi.LoginModule;
30
31
32 /***
33 * An implementation of {@link LoginModule} that uses an Acegi Security
34 * {@link org.acegisecurity.context.SecurityContext SecurityContext}
35 * to provide authentication. <br />
36 * This LoginModule provides opposite functionality to the {@link
37 * JaasAuthenticationProvider} API, and should not really be used in
38 * conjunction with it. <br />
39 * The {@link JaasAuthenticationProvider} allows Acegi to authenticate against
40 * Jaas. <br />
41 * The SecurityContextLoginModule allows a Jaas based application to
42 * authenticate against Acegi. If there is no Authentication in the {@link
43 * SecurityContextHolder} the login() method will throw a LoginException by
44 * default. This functionality can be changed with the
45 * <tt>ignoreMissingAuthentication</tt> option by setting it to "true".
46 * Setting ignoreMissingAuthentication=true will tell the
47 * SecurityContextLoginModule to simply return false and be ignored if the
48 * authentication is null.
49 *
50 * @author Brian Moseley
51 * @author Ray Krueger
52 */
53 public class SecurityContextLoginModule implements LoginModule {
54
55
56 private static final Log log = LogFactory.getLog(SecurityContextLoginModule.class);
57
58
59
60 private Authentication authen;
61 private Subject subject;
62 private boolean ignoreMissingAuthentication = false;
63
64
65
66 /***
67 * Abort the authentication process by forgetting the Acegi Security
68 * <code>Authentication</code>.
69 *
70 * @return true if this method succeeded, or false if this
71 * <code>LoginModule</code> should be ignored.
72 *
73 * @exception LoginException if the abort fails
74 */
75 public boolean abort() throws LoginException {
76 if (authen == null) {
77 return false;
78 }
79
80 authen = null;
81
82 return true;
83 }
84
85 /***
86 * Authenticate the <code>Subject</code> (phase two) by adding the Acegi
87 * Security <code>Authentication</code> to the <code>Subject</code>'s
88 * principals.
89 *
90 * @return true if this method succeeded, or false if this
91 * <code>LoginModule</code> should be ignored.
92 *
93 * @exception LoginException if the commit fails
94 */
95 public boolean commit() throws LoginException {
96 if (authen == null) {
97 return false;
98 }
99
100 subject.getPrincipals().add(authen);
101
102 return true;
103 }
104
105 /***
106 * Initialize this <code>LoginModule</code>. Ignores the callback handler,
107 * since the code establishing the <code>LoginContext</code> likely won't
108 * provide one that understands Acegi Security. Also ignores the
109 * <code>sharedState</code> and <code>options</code> parameters, since
110 * none are recognized.
111 *
112 * @param subject the <code>Subject</code> to be authenticated. <p>
113 * @param callbackHandler is ignored
114 * @param sharedState is ignored
115 * @param options are ignored
116 */
117 public void initialize(Subject subject, CallbackHandler callbackHandler,
118 Map sharedState, Map options) {
119 this.subject = subject;
120
121 if (options != null) {
122 ignoreMissingAuthentication = "true".equals(options.get(
123 "ignoreMissingAuthentication"));
124 }
125 }
126
127 /***
128 * Authenticate the <code>Subject</code> (phase one) by extracting the
129 * Acegi Security <code>Authentication</code> from the current
130 * <code>SecurityContext</code>.
131 *
132 * @return true if the authentication succeeded, or false if this
133 * <code>LoginModule</code> should be ignored.
134 *
135 * @throws LoginException if the authentication fails
136 */
137 public boolean login() throws LoginException {
138 authen = SecurityContextHolder.getContext().getAuthentication();
139
140 if (authen == null) {
141 String msg = "Login cannot complete, authentication not found in security context";
142
143 if (ignoreMissingAuthentication) {
144 log.warn(msg);
145
146 return false;
147 } else {
148 throw new LoginException(msg);
149 }
150 }
151
152 return true;
153 }
154
155 /***
156 * Log out the <code>Subject</code>.
157 *
158 * @return true if this method succeeded, or false if this
159 * <code>LoginModule</code> should be ignored.
160 *
161 * @exception LoginException if the logout fails
162 */
163 public boolean logout() throws LoginException {
164 if (authen == null) {
165 return false;
166 }
167
168 subject.getPrincipals().remove(authen);
169 authen = null;
170
171 return true;
172 }
173
174 Authentication getAuthentication() {
175 return authen;
176 }
177
178 Subject getSubject() {
179 return subject;
180 }
181 }