Skip to content

Commit

Permalink
Merge branch 'master' into authn-sup-mfa
Browse files Browse the repository at this point in the history
# Conflicts:
#	cas-server-core-authentication/src/test/java/org/jasig/cas/authentication/handler/support/SimpleTestUsernamePasswordAuthenticationHandler.java
  • Loading branch information
SavvasMisaghMoayyed committed Dec 14, 2015
1 parent a9fcf6b commit 37feb2e
Show file tree
Hide file tree
Showing 58 changed files with 705 additions and 636 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@
<bean id="attributeRepository" class="org.jasig.services.persondir.support.NamedStubPersonAttributeDao"/>
<alias name="inMemoryServiceRegistryDao" alias="serviceRegistryDao" />
<alias name="defaultPrincipalFactory" alias="principalFactory" />
<alias name="defaultAuthenticationSupervisor" alias="authenticationTransactionManager" />
<alias name="defaultAuthenticationTransactionManager" alias="authenticationTransactionManager" />
<alias name="defaultPrincipalElectionStrategy" alias="principalElectionStrategy" />
</beans>
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
<util:list id="serviceFactoryList" />
<alias name="acceptAnyAuthenticationPolicyFactory" alias="authenticationPolicyFactory" />
<alias name="defaultPrincipalFactory" alias="principalFactory" />
<alias name="defaultAuthenticationSupervisor" alias="authenticationTransactionManager" />
<alias name="defaultAuthenticationTransactionManager" alias="authenticationTransactionManager" />
<alias name="defaultPrincipalElectionStrategy" alias="principalElectionStrategy" />
</beans>
Original file line number Diff line number Diff line change
@@ -1,47 +1,25 @@
package org.jasig.cas.authentication;

/**
* This is {@link AuthenticationContextBuilder}. Builds an authentication context,
* and collects authentication events to form a line of history from which the primary
* composed context can be gleaned.
* This is {@link AuthenticationContextBuilder}.
*
* @author Misagh Moayyed
* @since 4.2.0
*/
public interface AuthenticationContextBuilder {
/**
* Total number of active authentications in this context.
*
* @return total count of authentications
*/
int size();

/**
* Determines whether the context is empty.
* A non-empty context must contain a primary authentication and principal.
*
* @return true if context is empty.
*/
boolean isEmpty();

/**
* Collect a new authenication event and store it.
* Collect authentication context builder.
*
* @param authentication the new authentication event
* @return the builder instance in a fluid manner
* @throws AuthenticationException the authentication exception
* @param authentication the authentication
* @return the authentication context builder
*/
AuthenticationContextBuilder collect(Authentication authentication) throws AuthenticationException;
AuthenticationContextBuilder collect(final Authentication authentication);

/**
* Build authentication context.
*
* @return the authentication context
*/
AuthenticationContext build();

/**
* Clear.
*/
void clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.jasig.cas.authentication;

/**
* This is {@link AuthenticationObjectsRepository}, that holds the authentication machinery objects.
* This component is to be injected into others where access to authentication object is required, and
* simply serves as a holder.
*
* @author Misagh Moayyed
* @since 4.2.0
*/
public interface AuthenticationObjectsRepository {

/**
* Gets authentication transaction manager.
*
* @return the authentication transaction manager
*/
AuthenticationTransactionManager getAuthenticationTransactionManager();

/**
* Gets authentication transaction factory.
*
* @return the authentication transaction factory
*/
AuthenticationTransactionFactory getAuthenticationTransactionFactory();

/**
* Gets principal election strategy.
*
* @return the principal election strategy
*/
PrincipalElectionStrategy getPrincipalElectionStrategy();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.jasig.cas.authentication;

import java.util.Collection;

/**
* This is {@link AuthenticationTransaction}.
*
* @author Misagh Moayyed
* @since 4.2.0
*/
public interface AuthenticationTransaction {

/**
* Gets credentials.
*
* @return the credentials
*/
Collection<Credential> getCredentials();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jasig.cas.authentication;

/**
* This is {@link AuthenticationTransactionFactory}.
*
* @author Misagh Moayyed
* @since 4.2.0
*/
public interface AuthenticationTransactionFactory {
/**
* Get authentication transaction.
*
* @param credentials the credentials
* @return the authentication transaction
*/
AuthenticationTransaction get(Credential... credentials);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,11 @@
*/
public interface AuthenticationTransactionManager {
/**
* Authenticate boolean.
*
* @param credentials the credentials
* @return the context builder
* @param authenticationTransaction the authn attempt
* @param authenticationContextBuilder the authentication context
* @return the transaction manager
* @throws AuthenticationException the authentication exception
*/
AuthenticationContextBuilder processAuthenticationAttempt(final Credential... credentials) throws AuthenticationException;

/**
* Build authentication context authentication context.
*
* @return the authentication context
*/
AuthenticationContext build();

/**
* Clear.
*/
void clear();
AuthenticationTransactionManager handle(AuthenticationTransaction authenticationTransaction,
AuthenticationContextBuilder authenticationContextBuilder) throws AuthenticationException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.jasig.cas.ticket.registry;


import org.jasig.cas.authentication.Authentication;
import org.jasig.cas.authentication.principal.Principal;

import java.util.Map;

/**
* Helper strategy API to ease retrieving CAS' <code>Authentication</code> object and its associated components
* from available CAS SSO String token called <i>Ticket Granting Ticket (TGT)</i>.
*
* @author Misagh Moayyed
* @author Dmitriy Kopylenko
* @since 4.2.0
*/
public interface TicketRegistrySupport {

/**
* Retrieve a valid Authentication object identified by the provided TGT SSO token.
* @param ticketGrantingTicketId an SSO token identifying the requested Authentication
* @return valid Authentication OR <b>NULL</b> if there is no valid SSO session present identified by the provided TGT id SSO token
* @throws RuntimeException
*/
Authentication getAuthenticationFrom(String ticketGrantingTicketId);

/**
* Retrieve a valid Principal object identified by the provided TGT SSO token.
* @param ticketGrantingTicketId an SSO token identifying the requested authenticated Principal
* @return valid Principal OR <b>NULL</b> if there is no valid SSO session present identified by the provided TGT id SSO token
* @throws RuntimeException
*/
Principal getAuthenticatedPrincipalFrom(String ticketGrantingTicketId);

/**
* Retrieve a valid Principal's map of attributes identified by the provided TGT SSO token.
* @param ticketGrantingTicketId an SSO token identifying the requested authenticated Principal's attributes
* @return valid Principal's attributes OR <b>NULL</b> if there is no valid SSO session
* present identified by the provided TGT id SSO token
* @throws RuntimeException
*/
Map<String, Object> getPrincipalAttributesFrom(String ticketGrantingTicketId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import org.aspectj.lang.JoinPoint;
import org.jasig.cas.AbstractCentralAuthenticationServiceTests;
import org.jasig.cas.authentication.AuthenticationContext;
import org.jasig.cas.authentication.AuthenticationContextBuilder;
import org.jasig.cas.authentication.AuthenticationException;
import org.jasig.cas.authentication.AuthenticationTransaction;
import org.jasig.cas.authentication.Credential;
import org.jasig.cas.authentication.DefaultAuthenticationContextBuilder;
import org.jasig.cas.authentication.TestUtils;
import org.jasig.cas.ticket.ServiceTicket;
import org.jasig.cas.ticket.TicketGrantingTicket;
Expand Down Expand Up @@ -44,9 +48,7 @@ public void verifyResolverCredential() {
@Test
public void verifyResolverServiceTicket() throws Exception {
final Credential c = TestUtils.getCredentialsWithSameUsernameAndPassword();

getAuthenticationTransactionManager().processAuthenticationAttempt(c);
final AuthenticationContext ctx = this.getAuthenticationTransactionManager().build();
final AuthenticationContext ctx = getAuthenticationContext(c);

final TicketGrantingTicket ticketId = getCentralAuthenticationService()
.createTicketGrantingTicket(ctx);
Expand All @@ -67,8 +69,7 @@ public void verifyResolverServiceTicket() throws Exception {
@Test
public void verifyResolverTicketGrantingTicket() throws Exception {
final Credential c = TestUtils.getCredentialsWithSameUsernameAndPassword();
getAuthenticationTransactionManager().processAuthenticationAttempt(c);
final AuthenticationContext ctx = this.getAuthenticationTransactionManager().build();
final AuthenticationContext ctx = getAuthenticationContext(c);

final TicketGrantingTicket ticketId = getCentralAuthenticationService()
.createTicketGrantingTicket(ctx);
Expand All @@ -85,4 +86,17 @@ public void verifyResolverTicketGrantingTicket() throws Exception {
assertNotNull(result);
assertEquals(result, c.getId());
}

private AuthenticationContext getAuthenticationContext(final Credential... credentials)
throws AuthenticationException {
final AuthenticationContextBuilder builder = new DefaultAuthenticationContextBuilder(
getAuthenticationObjectsRepository().getPrincipalElectionStrategy());
final AuthenticationTransaction transaction =
getAuthenticationObjectsRepository().getAuthenticationTransactionFactory()
.get(org.jasig.cas.authentication.TestUtils.getCredentialsWithSameUsernameAndPassword());
getAuthenticationObjectsRepository().getAuthenticationTransactionManager()
.handle(transaction, builder);
final AuthenticationContext ctx = builder.build();
return ctx;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.security.GeneralSecurityException;
import java.util.Arrays;
Expand All @@ -25,34 +22,27 @@
* @author Misagh Moayyed
* @since 4.2.0
*/
@Component("defaultAuthenticationContextBuilder")
public class DefaultAuthenticationContextBuilder implements AuthenticationContextBuilder {
public final class DefaultAuthenticationContextBuilder implements AuthenticationContextBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAuthenticationContextBuilder.class);

private final Set<Authentication> authentications = Collections.synchronizedSet(new LinkedHashSet<Authentication>());
private final ThreadLocal<Set<Authentication>> authentications = new ThreadLocal<>();

@Autowired
@Qualifier("principalElectionStrategy")
private PrincipalElectionStrategy principalElectionStrategy;

@Override
public int size() {
return this.authentications.size();
}

@Override
public boolean isEmpty() {
return this.authentications.isEmpty();
/**
* Instantiates a new Default authentication context builder.
*
* @param principalElectionStrategy the principal election strategy
*/
public DefaultAuthenticationContextBuilder(final PrincipalElectionStrategy principalElectionStrategy) {
this.principalElectionStrategy = principalElectionStrategy;
}

@Override
public AuthenticationContextBuilder collect(final Authentication authentication) throws AuthenticationException {
if (this.authentications.add(authentication)) {
LOGGER.debug("Collected authentication event. Associated principal with this authentication is [{}]",
authentication.getPrincipal());
} else {
LOGGER.warn("Failed to collect duplicate authentication event as it already exists.");
}
public AuthenticationContextBuilder collect(final Authentication authentication) {
final Set<Authentication> set = getAuthentications();
set.add(authentication);
this.authentications.set(set);
return this;
}

Expand All @@ -65,24 +55,31 @@ public AuthenticationContext build() {
return new DefaultAuthenticationContext(authentication);
}

@Override
public void clear() {
this.authentications.clear();
private Set<Authentication> getAuthentications() {
Set<Authentication> set = this.authentications.get();
if (set == null) {
set = Collections.synchronizedSet(new LinkedHashSet<Authentication>());
}
return set;
}

private boolean isEmpty() {
return getAuthentications().isEmpty();
}

private Authentication buildAuthentication() {
if (isEmpty()) {
LOGGER.warn("No authentication event has been recorded; CAS cannot finalize the authentication context");
return null;
}
final Set<Authentication> authentications = getAuthentications();

final Map<String, Object> authenticationAttributes = new HashMap<>();
final Map<String, Object> principalAttributes = new HashMap<>();
final AuthenticationBuilder authenticationBuilder = DefaultAuthenticationBuilder.newInstance();

buildAuthenticationHistory(authenticationAttributes, principalAttributes, authenticationBuilder);

final Principal primaryPrincipal = getPrimaryPrincipal(principalAttributes);
buildAuthenticationHistory(authentications, authenticationAttributes, principalAttributes, authenticationBuilder);
final Principal primaryPrincipal = getPrimaryPrincipal(authentications, principalAttributes);
authenticationBuilder.setPrincipal(primaryPrincipal);
LOGGER.debug("Determined primary authentication principal to be [{}]", primaryPrincipal);

Expand All @@ -97,12 +94,13 @@ private Authentication buildAuthentication() {

}

private void buildAuthenticationHistory(final Map<String, Object> authenticationAttributes,
private void buildAuthenticationHistory(final Set<Authentication> authentications,
final Map<String, Object> authenticationAttributes,
final Map<String, Object> principalAttributes,
final AuthenticationBuilder authenticationBuilder) {

LOGGER.debug("Collecting authentication history based on [{}] authentication events", this.authentications.size());
for (final Authentication authn : this.authentications) {
LOGGER.debug("Collecting authentication history based on [{}] authentication events", authentications.size());
for (final Authentication authn : authentications) {
final Principal authenticatedPrincipal = authn.getPrincipal();
LOGGER.debug("Evaluating authentication principal [{}] for inclusion in context", authenticatedPrincipal);

Expand Down Expand Up @@ -134,8 +132,8 @@ private void buildAuthenticationHistory(final Map<String, Object> authentication
authenticationAttributes);

authenticationBuilder.addSuccesses(authn.getSuccesses())
.addFailures(authn.getFailures())
.addCredentials(authn.getCredentials());
.addFailures(authn.getFailures())
.addCredentials(authn.getCredentials());
}
}

Expand All @@ -144,8 +142,8 @@ private void buildAuthenticationHistory(final Map<String, Object> authentication
* Based on that restriction, it's safe to simply grab the first principal id in the chain
* when composing the authentication chain for the caller.
*/
private Principal getPrimaryPrincipal(final Map<String, Object> principalAttributes) {
return this.principalElectionStrategy.nominate(ImmutableSet.copyOf(this.authentications), principalAttributes);
private Principal getPrimaryPrincipal(final Set<Authentication> authentications, final Map<String, Object> principalAttributes) {
return this.principalElectionStrategy.nominate(ImmutableSet.copyOf(authentications), principalAttributes);
}

/**
Expand Down
Loading

0 comments on commit 37feb2e

Please sign in to comment.