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    }