diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java index 3b9e5e3..20e136f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java @@ -139,7 +139,7 @@ public class CasLoginModule implements LoginModule { /** Unique suffix pattern appended to some service URLs to make them unique. */ protected static final Pattern UNIQUE_SUFFIX_PATTERN = - Pattern.compile(".*;uuid=\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12}"); + Pattern.compile("(.*);uuid=\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12}"); /** Logger instance */ protected final Logger logger = LoggerFactory.getLogger(getClass()); @@ -327,7 +327,7 @@ public class CasLoginModule implements LoginModule { final Matcher m = UNIQUE_SUFFIX_PATTERN.matcher(this.service); if (m.matches()) { this.servicePrincipal = this.service; - this.service = m.replaceFirst(""); + this.service = m.replaceFirst("$1"); } else { this.servicePrincipal = this.service + createUniqueSuffix(); } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java index d255f39..afa0555 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java @@ -24,6 +24,8 @@ import java.security.acl.Group; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; + import javax.security.auth.Subject; import javax.security.auth.login.LoginException; import org.jasig.cas.client.PublicTestHttpServer; @@ -45,10 +47,6 @@ public class CasLoginModuleTests { private static final String CONST_CAS_SERVER_URL = "http://localhost:8091/"; - private CasLoginModule module; - - private Subject subject; - private Map options; /* @AfterClass @@ -58,10 +56,7 @@ public class CasLoginModuleTests { @Before public void setUp() throws Exception { - module = new CasLoginModule(); - subject = new Subject(); options = new HashMap(); - options.put("service", "https://service.example.com/webapp"); options.put("ticketValidatorClass", "org.jasig.cas.client.validation.Cas20ServiceTicketValidator"); options.put("casServerUrlPrefix", CONST_CAS_SERVER_URL); options.put("proxyCallbackUrl", "https://service.example.com/webapp/proxy"); @@ -85,6 +80,8 @@ public class CasLoginModuleTests { + ""; server.content = RESPONSE.getBytes(server.encoding); + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); module.initialize( subject, new ServiceAndTicketCallbackHandler(SERVICE, TICKET), @@ -92,11 +89,47 @@ public class CasLoginModuleTests { options); module.login(); module.commit(); - assertEquals(this.subject.getPrincipals().size(), 3); - assertEquals(TICKET, this.subject.getPrivateCredentials().iterator().next().toString()); - assertTrue(hasPrincipalName(this.subject, AssertionPrincipal.class, USERNAME)); - assertTrue(hasPrincipalName(this.subject, Group.class, "CallerPrincipal")); - assertTrue(hasPrincipalName(this.subject, Group.class, "Roles")); + assertEquals(subject.getPrincipals().size(), 3); + assertEquals(TICKET, subject.getPrivateCredentials().iterator().next().toString()); + assertTrue(hasPrincipalName(subject, Group.class, "CallerPrincipal")); + assertTrue(hasPrincipalName(subject, Group.class, "Roles")); + final AssertionPrincipal principal = getPrincipal(subject, AssertionPrincipal.class); + assertEquals(USERNAME, principal.getName()); + final Matcher m = CasLoginModule.UNIQUE_SUFFIX_PATTERN.matcher(principal.getServicePrincipal()); + assertTrue(m.matches()); + } + + + /** + * Test JAAS login success. + * @throws Exception On errors. + */ + @Test + public void testLoginSuccessUniquePrincipal() throws Exception { + final String USERNAME = "alice"; + final String SERVICE = "https://example.com/service" + CasLoginModule.createUniqueSuffix(); + final String TICKET = "ST-100001-aA5Zabcxzpv8Tau1abeZ-srv1"; + final String RESPONSE = "" + + "" + USERNAME + + ""; + server.content = RESPONSE.getBytes(server.encoding); + + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); + module.initialize( + subject, + new ServiceAndTicketCallbackHandler(SERVICE, TICKET), + new HashMap(), + options); + module.login(); + module.commit(); + assertEquals(subject.getPrincipals().size(), 3); + assertEquals(TICKET, subject.getPrivateCredentials().iterator().next().toString()); + assertTrue(hasPrincipalName(subject, Group.class, "CallerPrincipal")); + assertTrue(hasPrincipalName(subject, Group.class, "Roles")); + final AssertionPrincipal principal = getPrincipal(subject, AssertionPrincipal.class); + assertEquals(USERNAME, principal.getName()); + assertEquals(SERVICE, principal.getServicePrincipal()); } /** @@ -109,6 +142,9 @@ public class CasLoginModuleTests { final String TICKET = "ST-200000-aA5Yuvrxzpv8Tau1cYQ7-srv1"; final String RESPONSE = "Ticket ST-200000-aA5Yuvrxzpv8Tau1cYQ7-srv1 not recognized"; server.content = RESPONSE.getBytes(server.encoding); + + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); module.initialize( subject, new ServiceAndTicketCallbackHandler(SERVICE, TICKET), @@ -131,7 +167,32 @@ public class CasLoginModuleTests { */ @Test public void testLogout() throws Exception { - testLoginSuccess(); + final String USERNAME = "username"; + final String SERVICE = "https://example.com/service"; + final String TICKET = "ST-100000-aA5Yuvrxzpv8Tau1cYQ7-srv1"; + final String RESPONSE = "" + + "" + USERNAME + + ""; + server.content = RESPONSE.getBytes(server.encoding); + + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); + module.initialize( + subject, + new ServiceAndTicketCallbackHandler(SERVICE, TICKET), + new HashMap(), + options); + module.login(); + module.commit(); + assertEquals(subject.getPrincipals().size(), 3); + assertEquals(TICKET, subject.getPrivateCredentials().iterator().next().toString()); + assertTrue(hasPrincipalName(subject, Group.class, "CallerPrincipal")); + assertTrue(hasPrincipalName(subject, Group.class, "Roles")); + final AssertionPrincipal principal = getPrincipal(subject, AssertionPrincipal.class); + assertEquals(USERNAME, principal.getName()); + final Matcher m = CasLoginModule.UNIQUE_SUFFIX_PATTERN.matcher(principal.getServicePrincipal()); + assertTrue(m.matches()); + module.logout(); assertEquals(0, subject.getPrincipals().size()); assertEquals(0, subject.getPrivateCredentials().size()); @@ -155,6 +216,9 @@ public class CasLoginModuleTests { options.put("cacheTimeout", "1"); server.content = SUCCESS_RESPONSE.getBytes(server.encoding); + + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); module.initialize( subject, new ServiceAndTicketCallbackHandler(SERVICE, TICKET), @@ -162,8 +226,8 @@ public class CasLoginModuleTests { options); module.login(); module.commit(); - assertEquals(this.subject.getPrincipals().size(), 3); - assertEquals(TICKET, this.subject.getPrivateCredentials().iterator().next().toString()); + assertEquals(subject.getPrincipals().size(), 3); + assertEquals(TICKET, subject.getPrivateCredentials().iterator().next().toString()); // Logout should destroy all authenticated state data including assertion cache entries module.logout(); @@ -184,8 +248,8 @@ public class CasLoginModuleTests { } catch (LoginException e) { assertEquals(TicketValidationException.class, e.getCause().getClass()); } - assertEquals(0, this.subject.getPrincipals().size()); - assertEquals(0, this.subject.getPrivateCredentials().size()); + assertEquals(0, subject.getPrincipals().size()); + assertEquals(0, subject.getPrivateCredentials().size()); } /** @@ -210,6 +274,9 @@ public class CasLoginModuleTests { options.put("cacheTimeout", "1"); server.content = SUCCESS_RESPONSE.getBytes(server.encoding); + + final CasLoginModule module = new CasLoginModule(); + final Subject subject = new Subject(); module.initialize( subject, new ServiceAndTicketCallbackHandler(SERVICE, TICKET), @@ -234,6 +301,11 @@ public class CasLoginModuleTests { } } + private T getPrincipal(final Subject subject, final Class principalType) + { + return subject.getPrincipals(principalType).iterator().next(); + } + private boolean hasPrincipalName(final Subject subject, final Class principalClass, final String name) { final Set principals = subject.getPrincipals(principalClass);