package org.broadleafcommerce.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.CredentialsExpiredException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.security.util.TextUtils;

public class BCAuthenticationProcessingFilter extends AuthenticationProcessingFilter {

    private final List<PostLoginObserver> postLoginListeners = new ArrayList<PostLoginObserver>();

    private String passwordChangeUri = "/passwordChange.htm";

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
        Authentication auth = null;
        try {
            auth = super.attemptAuthentication(request);
        } catch (CredentialsExpiredException e) {
            String username = obtainUsername(request);
            String password = obtainPassword(request);

            if (username == null) {
                username = "";
            }

            if (password == null) {
                password = "";
            }

            username = username.trim();

            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password, new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_PASSWORD_CHANGE_REQUIRED") });

            // Place the last username attempted into HttpSession for views
            HttpSession session = request.getSession(false);

            if (session != null || getAllowSessionCreation()) {
                request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextUtils.escapeEntities(username));
            }

            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            auth = authRequest;
        }
        return auth;
    }

    @Override
    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
        super.onSuccessfulAuthentication(request, response, authResult);
        notifyListeners(request, response, authResult);
    }

    @Override
    protected String determineTargetUrl(HttpServletRequest request) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        for (GrantedAuthority ga : auth.getAuthorities()) {
            if ("ROLE_PASSWORD_CHANGE_REQUIRED".equals(ga.getAuthority())) {
                return passwordChangeUri;
            }
        }
        String successUrlParam = request.getParameter("successUrl");
        if (StringUtils.isNotEmpty(successUrlParam)) {
            return successUrlParam;
        }
        return super.determineTargetUrl(request);
    }

    @Override
    protected String determineFailureUrl(HttpServletRequest request, AuthenticationException failed) {
        String failureUrlParam = request.getParameter("failureUrl");
        if (StringUtils.isNotEmpty(failureUrlParam)) {
            String failureUrl = failureUrlParam;
            String successUrlParam = request.getParameter("successUrl");
            if (StringUtils.isNotEmpty(successUrlParam)) {
                if (failureUrl.contains("?")) {
                    failureUrl += "?successUrl=" + successUrlParam;
                } else {
                    failureUrl += "&successUrl=" + successUrlParam;
                }
            }
            return failureUrl;
        }
        return super.determineFailureUrl(request, failed);
    }

    public void addListener(PostLoginObserver postLoginObserver) {
        this.postLoginListeners.add(postLoginObserver);
    }

    public void removeListener(PostLoginObserver postLoginObserver) {
        if (this.postLoginListeners.contains(postLoginObserver)) {
            this.postLoginListeners.remove(postLoginObserver);
        }
    }

    public void notifyListeners(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
        for (Iterator<PostLoginObserver> iter = postLoginListeners.iterator(); iter.hasNext();) {
            PostLoginObserver listener = iter.next();
            listener.processPostLogin(request, response, authResult);
        }
    }

    public void setPasswordChangeUri(String passwordChangeUri) {
        this.passwordChangeUri = passwordChangeUri;
    }
}

@@ -3630,32 +3630,137 @@
 %22failureUrl%22);%0D%0A
+        String successUrlParam = request.getParameter(%22successUrl%22);%0D%0A        String failureUrl = null;%0D%0A
         if (Stri
@@ -3803,39 +3803,32 @@
  %7B%0D%0A            
-String 
 failureUrl = fai
@@ -3854,78 +3854,92 @@
     
-    String successUrlParam = request.getParameter(%22successUrl%22
+%7D else %7B%0D%0A            failureUrl = super.determineFailureUrl(request, failed
 );%0D%0A    
     
@@ -3926,32 +3926,39 @@
 , failed);%0D%0A    
+ 
+   %7D%0D%0A
         if (Stri
@@ -4009,24 +4009,21 @@
         
-    
 if (
+!
 failureU
@@ -4051,36 +4051,32 @@
                 
-  
-  
 failureUrl += %22?
@@ -4116,28 +4116,24 @@
             
-    
 %7D else %7B%0D%0A  
@@ -4138,36 +4138,32 @@
                 
-   
- 
 failureUrl += %22&
@@ -4203,35 +4203,27 @@
             
-    %7D%0D%0A    
+%7D%0D%0A
         %7D%0D%0A 
@@ -4225,28 +4225,24 @@
  %7D%0D%0A        
-    
 return failu
@@ -4253,79 +4253,8 @@
 l;%0D%0A
-        %7D%0D%0A        return super.determineFailureUrl(request, failed);%0D%0A
     

add failureUrl to login query string