001 /*
002 * $Id: LoginService.java 3360 2009-06-14 20:29:45Z kschaefe $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021 package org.jdesktop.swingx.auth;
022
023 import java.awt.EventQueue;
024 import java.util.logging.Logger;
025
026 import javax.swing.SwingUtilities;
027 import javax.swing.SwingWorker;
028 import javax.swing.event.EventListenerList;
029
030 import org.jdesktop.beans.AbstractBean;
031
032 /**
033 * <b>LoginService</b> is the abstract base class for all classes implementing
034 * a login mechanism. It allows you to customize the threading behaviour used to
035 * perform the login. Subclasses need to override the <b>authenticate</b>
036 * method. Subclasses may implement the getUserRoles() method to return a
037 * meaningful value this method will be called once upon a successful login to
038 * determine the user roles. It is not defined as abstract to simplify the task
039 * of implementing a login service for those who do not require this
040 * functionality.
041 *
042 * @author Bino George
043 * @author Shai Almog
044 * @author Karl Schaefer
045 */
046 public abstract class LoginService extends AbstractBean {
047 private Logger LOG = Logger.getLogger(LoginService.class.getName());
048
049 private EventListenerList listenerList = new EventListenerList();
050
051 private SwingWorker<Boolean, Void> loginWorker;
052
053 /*
054 * Controls the authentication behaviour to be either synchronous or
055 * asynchronous
056 */
057 private boolean synchronous;
058
059 private String server;
060
061 public LoginService() {
062 }
063
064 public LoginService(String server) {
065 setServer(server);
066 }
067
068 /**
069 * This method is intended to be implemented by clients wishing to
070 * authenticate a user with a given password. Clients should implement the
071 * authentication in a manner that the authentication can be cancelled at
072 * any time.
073 *
074 * @param name
075 * username
076 * @param password
077 * password
078 * @param server
079 * server (optional)
080 *
081 * @return <code>true</code> on authentication success
082 * @throws Exception
083 */
084 public abstract boolean authenticate(String name, char[] password,
085 String server) throws Exception;
086
087 /**
088 * Called immediately after a successful authentication. This method should
089 * return an array of user roles or null if role based permissions are not
090 * used.
091 *
092 * @return per default <code>null</code>
093 */
094 public String[] getUserRoles() {
095 return null;
096 }
097
098 /**
099 * Notifies the LoginService that an already running authentication request
100 * should be cancelled. This method is intended to be used by clients who
101 * want to provide user with control over cancelling a long running
102 * authentication request.
103 */
104 public void cancelAuthentication() {
105 if (loginWorker != null) {
106 loginWorker.cancel(true);
107 }
108 }
109
110 /**
111 * This method starts the authentication process and is either synchronous
112 * or asynchronous based on the synchronous property
113 *
114 * @param user
115 * user
116 * @param password
117 * password
118 * @param server
119 * server
120 * @throws Exception
121 */
122 public void startAuthentication(final String user, final char[] password,
123 final String server) throws Exception {
124 if (getSynchronous()) {
125 try {
126 if (authenticate(user, password, server)) {
127 fireLoginSucceeded(new LoginEvent(this));
128 } else {
129 fireLoginFailed(new LoginEvent(this));
130 }
131 } catch (Throwable e) {
132 fireLoginFailed(new LoginEvent(this, e));
133 }
134 } else {
135 loginWorker = new SwingWorker<Boolean, Void>() {
136 protected Boolean doInBackground() throws Exception {
137 try {
138 final boolean result = authenticate(user, password,
139 server);
140 if (isCancelled()) {
141 EventQueue.invokeLater(new Runnable() {
142 public void run() {
143 fireLoginCanceled(new LoginEvent(this));
144 }
145 });
146 return false;
147 }
148 EventQueue.invokeLater(new Runnable() {
149 public void run() {
150 if (result) {
151 fireLoginSucceeded(new LoginEvent(
152 LoginService.this));
153 } else {
154 fireLoginFailed(new LoginEvent(
155 LoginService.this));
156 }
157 }
158 });
159 return result;
160 } catch (final Throwable failed) {
161 if (!isCancelled()) {
162 SwingUtilities.invokeLater(new Runnable() {
163 public void run() {
164 fireLoginFailed(new LoginEvent(
165 LoginService.this, failed));
166 }
167 });
168 } else {
169 EventQueue.invokeLater(new Runnable() {
170 public void run() {
171 fireLoginCanceled(new LoginEvent(this));
172 }
173 });
174 }
175 return false;
176 }
177 }
178 };
179 loginWorker.execute();
180 fireLoginStarted(new LoginEvent(this));
181 }
182 }
183
184 /**
185 * Get the synchronous property
186 *
187 * @return the synchronous property
188 */
189 public boolean getSynchronous() {
190 return synchronous;
191 }
192
193 /**
194 * Sets the synchronous property
195 *
196 * @param synchronous
197 * synchronous property
198 */
199 public void setSynchronous(boolean synchronous) {
200 boolean old = getSynchronous();
201 this.synchronous = synchronous;
202 firePropertyChange("synchronous", old, getSynchronous());
203 }
204
205 /**
206 * Adds a <strong>LoginListener</strong> to the list of listeners
207 *
208 * @param listener
209 * listener
210 */
211
212 public void addLoginListener(LoginListener listener) {
213 listenerList.add(LoginListener.class, listener);
214 }
215
216 /**
217 * Removes a <strong>LoginListener</strong> from the list of listeners
218 *
219 * @param listener
220 * listener
221 */
222 public void removeLoginListener(LoginListener listener) {
223 listenerList.remove(LoginListener.class, listener);
224 }
225
226 void fireLoginStarted(final LoginEvent source) {
227 // Guaranteed to return a non-null array
228 Object[] listeners = listenerList.getListenerList();
229 // Process the listeners last to first, notifying
230 // those that are interested in this event
231 for (int i = listeners.length-2; i>=0; i-=2) {
232 if (listeners[i] == LoginListener.class) {
233 ((LoginListener) listeners[i+1]).loginStarted(source);
234 }
235 }
236 }
237
238 void fireLoginSucceeded(final LoginEvent source) {
239 // Guaranteed to return a non-null array
240 Object[] listeners = listenerList.getListenerList();
241 // Process the listeners last to first, notifying
242 // those that are interested in this event
243 for (int i = listeners.length-2; i>=0; i-=2) {
244 if (listeners[i] == LoginListener.class) {
245 ((LoginListener) listeners[i+1]).loginSucceeded(source);
246 }
247 }
248 }
249
250 void fireLoginFailed(final LoginEvent source) {
251 // Guaranteed to return a non-null array
252 Object[] listeners = listenerList.getListenerList();
253 // Process the listeners last to first, notifying
254 // those that are interested in this event
255 for (int i = listeners.length-2; i>=0; i-=2) {
256 if (listeners[i] == LoginListener.class) {
257 ((LoginListener) listeners[i+1]).loginFailed(source);
258 }
259 }
260 }
261
262 void fireLoginCanceled(final LoginEvent source) {
263 // Guaranteed to return a non-null array
264 Object[] listeners = listenerList.getListenerList();
265 // Process the listeners last to first, notifying
266 // those that are interested in this event
267 for (int i = listeners.length-2; i>=0; i-=2) {
268 if (listeners[i] == LoginListener.class) {
269 ((LoginListener) listeners[i+1]).loginCanceled(source);
270 }
271 }
272 }
273
274 /**
275 * @return Returns the server.
276 */
277 public String getServer() {
278 return server;
279 }
280
281 /**
282 * @param server
283 * The server to set.
284 */
285 public void setServer(String server) {
286 String old = getServer();
287 this.server = server;
288 firePropertyChange("server", old, getServer());
289 }
290 }