From 5db2d5e3786f5851d8961467a2d6b04d895030ad Mon Sep 17 00:00:00 2001 From: Jozef Kotlar Date: Tue, 30 Oct 2012 14:28:35 +0100 Subject: [PATCH] implemented authentificator for Confluence 3.5 for newer Seraph/Crowd infrastructure - using getUserFromSession() - propagating event - based on https://bitbucket.org/jaysee00/example-confluence-sso-authenticator - based on comment from https://jira.atlassian.com/browse/CONF-26547 --- cas-client-integration-atlassian/pom.xml | 2 +- .../Confluence35CasAuthenticator.java | 107 ++++++++++++++++++ .../atlassian/Jira44CasAuthenticator.java | 40 ++++--- 3 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Confluence35CasAuthenticator.java diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index a8dc320..043b340 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -42,7 +42,7 @@ com.atlassian.confluence confluence - 3.4.4 + 3.5 provided diff --git a/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Confluence35CasAuthenticator.java b/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Confluence35CasAuthenticator.java new file mode 100644 index 0000000..2cb814f --- /dev/null +++ b/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Confluence35CasAuthenticator.java @@ -0,0 +1,107 @@ +/** + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jasig.cas.client.integration.atlassian; + +import com.atlassian.confluence.event.events.security.LoginEvent; +import com.atlassian.confluence.event.events.security.LoginFailedEvent; +import com.atlassian.confluence.user.ConfluenceAuthenticator; +import com.atlassian.seraph.auth.AuthenticatorException; +import com.atlassian.seraph.auth.LoginReason; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jasig.cas.client.util.AbstractCasFilter; +import org.jasig.cas.client.validation.Assertion; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.security.Principal; + +/** + * Extension of ConfluenceAuthenticator to allow people to configure Confluence 3.5+ to authenticate + * via CAS. + * + * Based on https://bitbucket.org/jaysee00/example-confluence-sso-authenticator + * + * @author Scott Battaglia + * @author John Watson + * @author Jozef Kotlar + * @version $Revision$ $Date$ + * @since 3.3.0 + */ +public final class Confluence35CasAuthenticator extends ConfluenceAuthenticator { + private static final long serialVersionUID = -6097438206488390678L; + + private static final Log LOG = LogFactory.getLog(Confluence35CasAuthenticator.class); + + public Principal getUser(final HttpServletRequest request, final HttpServletResponse response) { + Principal existingUser = getUserFromSession(request); + if (existingUser != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Session found; user already logged in."); + } + return existingUser; + } + + final HttpSession session = request.getSession(); + final Assertion assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); + + if (assertion != null) { + final String username = assertion.getPrincipal().getName(); + final Principal user = getUser(username); + final String remoteIP = request.getRemoteAddr(); + final String remoteHost = request.getRemoteHost(); + + if (user != null) { + putPrincipalInSessionContext(request, user); + getElevatedSecurityGuard().onSuccessfulLoginAttempt(request, username); + // Firing this event is necessary to ensure the user's personal information is intialised correctly. + getEventPublisher().publish(new LoginEvent(this, username, request.getSession().getId(), remoteHost, remoteIP)); + LoginReason.OK.stampRequestResponse(request, response); + if (LOG.isDebugEnabled()) { + LOG.debug("Logging in [" + username + "] from CAS."); + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Failed logging [" + username + "] from CAS."); + } + getElevatedSecurityGuard().onFailedLoginAttempt(request, username); + getEventPublisher().publish(new LoginFailedEvent(this, username, request.getSession().getId(), remoteHost, remoteIP)); + } + return user; + } + + return super.getUser(request, response); + } + + public boolean logout(final HttpServletRequest request, final HttpServletResponse response) throws AuthenticatorException { + final HttpSession session = request.getSession(); + + final Principal principal = (Principal) session.getAttribute(LOGGED_IN_KEY); + + if (LOG.isDebugEnabled() && principal != null) { + LOG.debug("Logging out [" + principal.getName() + "] from CAS."); + } + + removePrincipalFromSessionContext(request); + session.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, null); + return true; + } +} \ No newline at end of file diff --git a/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Jira44CasAuthenticator.java b/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Jira44CasAuthenticator.java index 493aa61..689561d 100644 --- a/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Jira44CasAuthenticator.java +++ b/cas-client-integration-atlassian/src/main/java/org/jasig/cas/client/integration/atlassian/Jira44CasAuthenticator.java @@ -21,6 +21,7 @@ package org.jasig.cas.client.integration.atlassian; import com.atlassian.jira.security.login.JiraSeraphAuthenticator; import com.atlassian.seraph.auth.AuthenticatorException; +import com.atlassian.seraph.auth.LoginReason; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.client.util.AbstractCasFilter; @@ -36,7 +37,8 @@ import java.security.Principal; * JIRA 4.4 and above to authenticate via Jasig CAS * * @author Scott Battaglia - * @author Martin Stiborský + * @author Martin Stiborsky + * @author Jozef Kotlar * @version $Revision$ $Date$ * @since 3.3.0 */ @@ -48,28 +50,35 @@ public final class Jira44CasAuthenticator extends JiraSeraphAuthenticator { private static final Log LOG = LogFactory.getLog(Jira44CasAuthenticator.class); public Principal getUser(final HttpServletRequest request, final HttpServletResponse response) { - final HttpSession session = request.getSession(); - - // user already exists - if (session.getAttribute(LOGGED_IN_KEY) != null) { + // First, check to see if this session has already been authenticated during a previous request. + Principal existingUser = getUserFromSession(request); + if (existingUser != null) { if (LOG.isDebugEnabled()) { LOG.debug("Session found; user already logged in."); } - return (Principal) session.getAttribute(LOGGED_IN_KEY); } + final HttpSession session = request.getSession(); final Assertion assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); if (assertion != null) { - final Principal p = getUser(assertion.getPrincipal().getName()); + final String username = assertion.getPrincipal().getName(); + final Principal user = getUser(username); - if (LOG.isDebugEnabled()) { - LOG.debug("Logging in [" + p.getName() + "] from CAS."); + if (user != null) { + putPrincipalInSessionContext(request, user); + getElevatedSecurityGuard().onSuccessfulLoginAttempt(request, username); + LoginReason.OK.stampRequestResponse(request, response); + if (LOG.isDebugEnabled()) { + LOG.debug("Logging in [" + username + "] from CAS."); + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Failed logging [" + username + "] from CAS."); + } + getElevatedSecurityGuard().onFailedLoginAttempt(request, username); } - - session.setAttribute(LOGGED_IN_KEY, p); - session.setAttribute(LOGGED_OUT_KEY, null); - return p; + return user; } return super.getUser(request, response); @@ -79,12 +88,11 @@ public final class Jira44CasAuthenticator extends JiraSeraphAuthenticator { final HttpSession session = request.getSession(); final Principal p = (Principal) session.getAttribute(LOGGED_IN_KEY); - if (LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled() && p != null) { LOG.debug("Logging out [" + p.getName() + "] from CAS."); } - session.setAttribute(LOGGED_OUT_KEY, p); - session.setAttribute(LOGGED_IN_KEY, null); + removePrincipalFromSessionContext(request); session.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, null); return true; }