package org.apereo.cas.support.openid.web.flow;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.CasProtocolConstants;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.adaptive.AdaptiveAuthenticationPolicy;
import org.apereo.cas.authentication.principal.Principal;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.support.openid.OpenIdProtocolConstants;
import org.apereo.cas.support.openid.authentication.principal.OpenIdCredential;
import org.apereo.cas.support.openid.authentication.principal.OpenIdService;
import org.apereo.cas.support.openid.web.support.DefaultOpenIdUserNameExtractor;
import org.apereo.cas.support.openid.web.support.OpenIdUserNameExtractor;
import org.apereo.cas.ticket.registry.TicketRegistrySupport;
import org.apereo.cas.web.flow.AbstractNonInteractiveCredentialsAction;
import org.apereo.cas.web.flow.resolver.CasDelegatingWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver;
import org.apereo.cas.web.support.WebUtils;
import org.springframework.webflow.execution.RequestContext;
/**
* Attempts to utilize an existing single sign on session, but only if the
* Principal of the existing session matches the new Principal. Note that care
* should be taken when using credentials that are automatically provided and
* not entered by the user.
*
* @author Scott Battaglia
* @since 3.1
*/
public class OpenIdSingleSignOnAction extends AbstractNonInteractiveCredentialsAction {
private OpenIdUserNameExtractor extractor = new DefaultOpenIdUserNameExtractor();
private final TicketRegistrySupport ticketRegistrySupport;
public OpenIdSingleSignOnAction(final CasDelegatingWebflowEventResolver initialAuthenticationAttemptWebflowEventResolver,
final CasWebflowEventResolver serviceTicketRequestWebflowEventResolver,
final AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy, final OpenIdUserNameExtractor extractor,
final TicketRegistrySupport ticketRegistrySupport) {
super(initialAuthenticationAttemptWebflowEventResolver, serviceTicketRequestWebflowEventResolver, adaptiveAuthenticationPolicy);
this.extractor = extractor;
this.ticketRegistrySupport = ticketRegistrySupport;
}
@Override
protected Credential constructCredentialsFromRequest(final RequestContext context) {
final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
final String openidIdentityParameter = context.getRequestParameters().get(OpenIdProtocolConstants.OPENID_IDENTITY);
final String userName = getOpenIdSelectedIdentifier(context, ticketGrantingTicketId, openidIdentityParameter);
final Service service = WebUtils.getService(context);
// clear the service because otherwise we can fake the username
if (service instanceof OpenIdService && StringUtils.isBlank(userName)) {
context.getFlowScope().remove(CasProtocolConstants.PARAMETER_SERVICE);
}
if (StringUtils.isBlank(ticketGrantingTicketId) || StringUtils.isBlank(userName)) {
return null;
}
return new OpenIdCredential(ticketGrantingTicketId, userName);
}
private String getOpenIdSelectedIdentifier(final RequestContext context, final String ticketGrantingTicketId,
final String openidIdentityParameter) {
if (OpenIdProtocolConstants.OPENID_IDENTIFIERSELECT.equals(openidIdentityParameter)) {
context.getFlowScope().remove(OpenIdProtocolConstants.OPENID_LOCALID);
final Principal p = ticketRegistrySupport.getAuthenticatedPrincipalFrom(ticketGrantingTicketId);
if (p != null) {
return p.getId();
}
return OpenIdProtocolConstants.OPENID_IDENTIFIERSELECT;
}
final String userName = this.extractor.extractLocalUsernameFromUri(openidIdentityParameter);
context.getFlowScope().put(OpenIdProtocolConstants.OPENID_LOCALID, userName);
return userName;
}
}