Skip to content

Commit

Permalink
Merge pull request #2 from fcrespel/SECURITY-901
Browse files Browse the repository at this point in the history
Fix login redirect loop caused by SECURITY-901 changes in Jenkins core
  • Loading branch information
fcrespel authored Jan 21, 2019
2 parents 7a8bfa2 + 08e84b0 commit 85e348c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 22 deletions.
21 changes: 15 additions & 6 deletions src/main/java/org/jenkinsci/plugins/cas/CasSecurityRealm.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import org.apache.commons.lang.StringUtils;
import org.jasig.cas.client.session.SessionMappingStorage;
import org.jasig.cas.client.util.CommonUtils;
import org.jenkinsci.plugins.cas.spring.security.AcegiAuthenticationManager;
import org.jenkinsci.plugins.cas.spring.security.CasAuthentication;
import org.jenkinsci.plugins.cas.spring.security.CasRestAuthenticator;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.context.WebApplicationContext;
Expand All @@ -40,10 +42,10 @@
import hudson.model.Descriptor;
import hudson.security.ChainedServletFilter;
import hudson.security.SecurityRealm;
import hudson.security.SecurityRealm.SecurityComponents;
import hudson.util.FormValidation;
import hudson.util.spring.BeanBuilder;
import jenkins.model.Jenkins;
import jenkins.security.SecurityListener;

/**
* CAS Single Sign-On security realm.
Expand Down Expand Up @@ -244,7 +246,7 @@ public Filter createFilter(FilterConfig filterConfig) {
@Override
public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
// Clear Spring Security context
SecurityContextHolder.clearContext();
org.springframework.security.core.context.SecurityContextHolder.clearContext();

// Remove session from CAS single sign-out storage
HttpSession session = req.getSession(false);
Expand All @@ -270,13 +272,20 @@ public void doCommenceLogin(StaplerRequest req, StaplerResponse rsp) throws IOEx
}

/**
* The login process finishes here, although by the time this action is called
* everything has already been taken care of by filters.
* The login process finishes here, by mapping the Spring Security
* authentication back to Acegi and by firing the authenticated event.
* @param req request
* @param rsp response
*/
public void doFinishLogin(StaplerRequest req, StaplerResponse rsp) {
// Nothing to do
org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof CasAuthenticationToken) {
org.springframework.security.core.context.SecurityContextHolder.clearContext();
CasAuthenticationToken casToken = (CasAuthenticationToken) authentication;
CasAuthentication casAuth = CasAuthentication.newInstance(casToken);
SecurityContextHolder.getContext().setAuthentication(casAuth);
SecurityListener.fireAuthenticated(casAuth.getUserDetails());
}
}

// ~ SecurityRealm descriptor =======================================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@
import java.util.Collection;
import java.util.Map;

import org.acegisecurity.context.SecurityContextHolder;
import org.jenkinsci.plugins.cas.spring.security.CasAuthentication;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import hudson.tasks.Mailer;

Expand All @@ -36,16 +34,20 @@ public class CasEventListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AuthenticationSuccessEvent) {
onSuccessfulAuthentication(((AuthenticationSuccessEvent) event).getAuthentication());
} else if (event instanceof InteractiveAuthenticationSuccessEvent) {
onSuccessfulInteractiveAuthentication(((InteractiveAuthenticationSuccessEvent) event).getAuthentication());
}
}

/**
* Successful authentication event handler.
* This event is fired immediately after authentication, before filter chain
* is invoked and before Spring security context is updated.
* @param authentication the successful authentication object
*/
protected void onSuccessfulAuthentication(Authentication authentication) {
// Set Spring security context early to allow Acegi mapping in CasSecurityRealm.doFinishLogin()
SecurityContextHolder.getContext().setAuthentication(authentication);

// Map user attributes
if (authentication instanceof CasAuthenticationToken) {
CasAuthenticationToken casToken = (CasAuthenticationToken) authentication;
try {
Expand All @@ -56,17 +58,6 @@ protected void onSuccessfulAuthentication(Authentication authentication) {
}
}

/**
* Successful interactive authentication event handler.
* @param authentication the successful authentication object
*/
protected void onSuccessfulInteractiveAuthentication(Authentication authentication) {
if (authentication instanceof CasAuthenticationToken) {
CasAuthenticationToken casToken = (CasAuthenticationToken) authentication;
SecurityContextHolder.getContext().setAuthentication(CasAuthentication.newInstance(casToken));
}
}

/**
* Sync user attributes with a CAS authentication token.
* @param casToken CAS authentication token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ casFilter(ChainedServletFilter) {
serviceProperties = casServiceProperties
authenticationFailureHandler = bean(SimpleUrlAuthenticationFailureHandler, "/" + securityRealm.failedLoginUrl)
authenticationSuccessHandler = bean(SessionUrlAuthenticationSuccessHandler, "/")
continueChainBeforeSuccessfulAuthentication = true
}
]
}
Expand Down

0 comments on commit 85e348c

Please sign in to comment.