package org.apereo.cas.adaptors.azure; import net.phonefactor.pfsdk.PFAuth; import net.phonefactor.pfsdk.PFAuthParams; import net.phonefactor.pfsdk.PFAuthResult; import org.apereo.cas.authentication.Credential; import org.apereo.cas.authentication.HandlerResult; import org.apereo.cas.authentication.PreventedException; import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler; import org.apereo.cas.authentication.principal.Principal; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.web.support.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.RequestContextHolder; import javax.security.auth.login.FailedLoginException; import java.security.GeneralSecurityException; /** * An authentication handler that uses the token provided * to authenticator against azure authN for MFA. * * @author Misagh Moayyed * @since 5.1.0 */ public class AzureAuthenticatorAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler { private static final Logger LOGGER = LoggerFactory.getLogger(AzureAuthenticatorAuthenticationHandler.class); private final PFAuth azureAuthenticatorInstance; private final AzureAuthenticatorAuthenticationRequestBuilder authenticationRequestBuilder; public AzureAuthenticatorAuthenticationHandler(final String name, final ServicesManager servicesManager, final PrincipalFactory principalFactory, final PFAuth azureAuthenticatorInstance, final AzureAuthenticatorAuthenticationRequestBuilder builder) { super(name, servicesManager, principalFactory, null); this.azureAuthenticatorInstance = azureAuthenticatorInstance; this.authenticationRequestBuilder = builder; } @Override protected HandlerResult doAuthentication(final Credential credential) throws GeneralSecurityException, PreventedException { try { final AzureAuthenticatorTokenCredential c = (AzureAuthenticatorTokenCredential) credential; final RequestContext context = RequestContextHolder.getRequestContext(); final Principal principal = WebUtils.getAuthentication(context).getPrincipal(); LOGGER.debug("Received principal id [{}]", principal.getId()); final PFAuthParams params = authenticationRequestBuilder.build(principal, c); final PFAuthResult r = azureAuthenticatorInstance.authenticate(params); if (r.getAuthenticated()) { return createHandlerResult(c, principalFactory.createPrincipal(principal.getId()), null); } LOGGER.error("Authentication failed. Call status: [{}]-[{}]. Error: [{}]", r.getCallStatus(), r.getCallStatusString(), r.getMessageError()); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); } throw new FailedLoginException("Failed to authenticate user"); } @Override public boolean supports(final Credential credential) { return AzureAuthenticatorTokenCredential.class.isAssignableFrom(credential.getClass()); } }