001 package org.springframework.richclient.security;
002
003 import java.io.Serializable;
004
005 import org.apache.commons.logging.Log;
006 import org.apache.commons.logging.LogFactory;
007 import org.springframework.context.ApplicationContext;
008 import org.springframework.rules.constraint.Constraint;
009 import org.springframework.richclient.application.Application;
010 import org.springframework.rules.PropertyConstraintProvider;
011 import org.springframework.rules.Rules;
012 import org.springframework.rules.constraint.property.PropertyConstraint;
013 import org.springframework.security.Authentication;
014 import org.springframework.security.AuthenticationManager;
015 import org.springframework.security.SpringSecurityException;
016 import org.springframework.security.context.SecurityContextHolder;
017 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
018
019 /**
020 * This class provides a bean suitable for use in a login form, providing properties for
021 * storing the user name and password. It also provides
022 * event firing for application security lifecycle. {@link LoginCommand} uses this
023 * object as its form object to collect the user name and password to use in an
024 * authentication request.
025 * <p>
026 * The actual authentication request is handled here, in the {@link #login()} method.
027 *
028 * <P>
029 * Temporarily stores the username and password provided by the user.
030 *
031 * @deprecated by the creation of new {@link ApplicationSecurityManager}
032 *
033 * @author Ben Alex
034 * @see ClientSecurityEvent
035 * @see LoginCommand
036 * @see LogoutCommand
037 */
038 public class SessionDetails implements Serializable, PropertyConstraintProvider {
039 public static final String PROPERTY_USERNAME = "username";
040
041 public static final String PROPERTY_PASSWORD = "password";
042
043 private static final Log logger = LogFactory.getLog( SessionDetails.class );
044
045 private transient AuthenticationManager authenticationManager;
046
047 private String username;
048
049 private String password;
050
051 private Rules validationRules;
052
053 public SessionDetails() {
054 // Retrieve any existing login information from the
055 // ContextHolder
056 if (SecurityContextHolder.getContext().getAuthentication() != null) {
057 setUsername(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
058 setPassword(SecurityContextHolder.getContext().getAuthentication().getCredentials().toString());
059 }
060 initRules();
061 }
062
063 protected void initRules() {
064 this.validationRules = new Rules(getClass()) {
065 protected void initRules() {
066 add(PROPERTY_USERNAME, all(new Constraint[] { required(), maxLength(getUsernameMaxLength()) }));
067 add(PROPERTY_PASSWORD, all(new Constraint[] { required(), minLength(getPasswordMinLength()) }));
068 }
069
070 protected int getUsernameMaxLength() {
071 return 8;
072 }
073
074 protected int getPasswordMinLength() {
075 return 2;
076 }
077
078 };
079 }
080
081 public PropertyConstraint getPropertyConstraint(String propertyName) {
082 return validationRules.getPropertyConstraint(propertyName);
083 }
084
085 public String getUsername() {
086 return username;
087 }
088
089 public void setUsername(String username) {
090 this.username = username;
091 }
092
093 public String getPassword() {
094 return password;
095 }
096
097 public void setPassword(String password) {
098 this.password = password;
099 }
100
101 public void setAuthenticationManager(AuthenticationManager manager) {
102 this.authenticationManager = manager;
103 }
104
105 public void login() throws SpringSecurityException {
106 final ApplicationContext appCtx = Application.instance().getApplicationContext();
107
108 // Attempt login
109 UsernamePasswordAuthenticationToken request = new UsernamePasswordAuthenticationToken(getUsername(),
110 getPassword());
111
112 Authentication result = null;
113
114 try {
115 result = authenticationManager.authenticate(request);
116 } catch( SpringSecurityException e ) {
117 logger.warn( "authentication failed", e);
118
119 // Fire application event to advise of failed login
120 appCtx.publishEvent( new AuthenticationFailedEvent(request, e));
121
122 // And rethrow the exception to prevent the dialog from closing
123 throw e;
124 }
125
126 // Handle success or failure of the authentication attempt
127 if( logger.isDebugEnabled()) {
128 logger.debug("successful login - update context holder and fire event");
129 }
130
131 // Commit the successful Authentication object to the secure
132 // ContextHolder
133 SecurityContextHolder.getContext().setAuthentication(result);
134
135 // Fire application event to advise of new login
136 appCtx.publishEvent(new LoginEvent(result));
137 }
138
139 public static Authentication logout() {
140 Authentication existing = SecurityContextHolder.getContext().getAuthentication();
141
142 // Make the Authentication object null if a SecureContext exists
143 SecurityContextHolder.getContext().setAuthentication(null);
144
145 // Create a non-null Authentication object if required (to meet
146 // ApplicationEvent contract)
147 if (existing == null) {
148 existing = ClientSecurityEvent.NO_AUTHENTICATION;
149 }
150
151 // Fire application event to advise of logout
152 ApplicationContext appCtx = Application.instance().getApplicationContext();
153 appCtx.publishEvent(new LogoutEvent(existing));
154
155 return existing;
156 }
157
158 }