Identityserver4: Forcing login on request to authorization endpoint - without using prompt

Created on 8 Feb 2018  路  5Comments  路  Source: IdentityServer/IdentityServer4

Hi,

I'm in a scenario where our SSO (identity server) has several clients. Different clients requires to be authenticated using different authentication methods.

QUESTION/TL;DR:
Can we force identity server to run our login logic when in an already authenticated state, without having the user include _prompt="login"_ in their auth request?

Background:
To make this work right now, we are doing the following:

  1. Add a custom property on our _ClientConfigs_ that takes a list of allowed authentication methods (I'll come back why we're not using the built in IdentityProviderRestrictions property)
  2. In our login logic, if we are already in an _Authenticated state_, we intersect _allowed authentication methods_ with _used authentication methods_ (retrieved via User.GetAuthenticationMethods()) to see if the we get a match. If we do, the authentication is fine and we just redirect back to the return url. Else, we force the user to login again, with a valid authentication method for the current client

It looks something like this (maybe the code explains it better than my words..):

```c#
var usedAuthenticatedMethods = User.GetAuthenticationMethods().Select(c => c.Value);
if (client.IsAuthenticatedWithAllowedMethod(usedAuthenticatedMethods))
return Redirect(returnUrl);

return GoToLogin(returnUrl, client);


3. When we login again, with a second authentication method, we do a new `SignInAsync`. We merge the already used with the new authentication method into the `authenticationMethods` parameter. This allows us to add more authentication methods to the current SSO session

**Forcing login on request to authorization endpoint**
To make this work, we obviously need to be able to run our login logic with every authorization request. Right now, the only solution we have found for this is to tell all our clients to include _prompt="login"_ in their auth requests.

We would really like to find a way to trigger this behavior without relying on our clients having to include the _prompt_ flag.

**`IdentityProviderRestrictions` and why we can't use it**
Identity server already supports a similar scenario with the  `IdentityProviderRestrictions` property on the `Client` class. Though the logic for checking that property is to see if the _currentIdp_ is in the _IdentityProviderRestrictions list_. This is not what we want, since the `currentIdp` is not the list of used authentication methods, but just a single instance of the idp used. From the source code ([link to code](https://github.com/IdentityServer/IdentityServer4/blob/becb2206826b1039687b3ec895fad5e1b26ef0c5/src/IdentityServer4/ResponseHandling/AuthorizeInteractionResponseGenerator.cs#L195)):

```c#
// check current idp
var currentIdp = request.Subject.GetIdentityProvider();

....

// check external idp restrictions if user not using local idp
else if (request.Client.IdentityProviderRestrictions != null && 
     request.Client.IdentityProviderRestrictions.Any() && 
    !request.Client.IdentityProviderRestrictions.Contains(currentIdp))
{
    Logger.LogInformation("Showing login: User is logged in with idp: {idp}, but idp not in client restriction list.", currentIdp);
    return new InteractionResponse { IsLogin = true };
}
question

All 5 comments

You can derive from our default authorize interaction generator - and always trigger login. Don't have a sample - but search for an interface with Interaction in it ;)

Thanks for a very quick response and a great product!

Following your suggestion worked fine for us. Here is a really quick explanation of we solved it, if someone finding the issue in the future would be interested :)

  1. Derived from AuthorizeInteractionResponseGenerator and overrode the ProcessLoginAsync method

```c#
public class ValidateAuthenticationMethodsAuthorizeInteractionResponseGenerator : AuthorizeInteractionResponseGenerator
{
public ValidateAuthenticationMethodsAuthorizeInteractionResponseGenerator(
ILogger logger,
IdentityServerOptions options,
IConsentService consent,
IProfileService profile,
IConfiguration configuration)
: base(logger, options, consent, profile)
{ }

protected override Task<InteractionResponse> ProcessLoginAsync(ValidatedAuthorizeRequest request)
{
    if (!request.Subject.IsAuthenticated())
    {
        return Task.FromResult(new InteractionResponse { IsLogin = true });
    }

    return ValidateUsedAuthenticationMethods(request); // Custom logic
}

....
}


2. Replace the default Identity Server implementation of `IAuthorizeInteractionResponseGenerator` with your custom implementation in DI

```c#
services.AddIdentityServer(...);

var validateAuthenticationMethodsResponseGenerator = new ServiceDescriptor(
    typeof(IAuthorizeInteractionResponseGenerator), 
    typeof(ValidateAuthenticationMethodsAuthorizeInteractionResponseGenerator), 
    ServiceLifetime.Transient);
services.Replace(validateAuthenticationMethodsResponseGenerator);

@fredrik-lundin

Hi, I implemented your code in your second post but it doesnt seems like ProcessLoginAsync gets executed.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings