IdentityServer UserService.IsActive Impersonation Redirect Loop
Asked Answered
C

0

7

I have implemented IsActive inside my custom user service and one of the steps that I do in that method is: check if the user has any roles for the requested client. If user has no roles IsActive will return false. This works well for regular scenarios. However once I implemented impersonation workflow, I started to get infinite redirects between login page and authorize endpoint.

I can implement the same IsActive check in my impersonate logic, but is there something else that I'm missing? It seems to me that I need to add something to IndentityServer so that it shows an error/not_authorized page, but I can't figure out where.

Implementation Details:

Impersonation is impelemented by retuning full AuthenticateResult from PreAuthenticateAsync based on custom acr_values.

var impersonate = context.SignInMessage.AcrValues.FirstOrDefault(x => x.StartsWith("impersonate"));

if (!string.IsNullOrWhiteSpace(impersonate))
{
    var adminUserName = _owinContext.Authentication.User.FindFirst(Constants.ClaimTypes.Subject).Value;
    var adminUser = _service.GetUser(adminUserName);
    bool isAllowedImpersonation = true; //TODO:

    var impersonateSplit = impersonate.Split(':');
    if (impersonateSplit.Length != 2 || !isAloowedImpersonation)
    {
        context.AuthenticateResult = new AuthenticateResult("Invalid attempt to impersonate user");
    }

    var impesonateUserName = impersonateSplit[1];
    var impersonateUser = _service.GetUser(impesonateUserName);

    context.AuthenticateResult =
        new AuthenticateResult(
            impersonateUser.Username,
            impersonateUser.Name,
            claims: new[] { new Claim(Constants.ClaimTypes.ClientId, context.SignInMessage.ClientId) },
            identityProvider: Constants.BuiltInIdentityProvider,
            authenticationMethod: Constants.AuthenticationMethods.Password);
}

Logic inside IsActive:

var user = _service.GetUser(context.Subject.GetSubjectId());

if (user == null || !user.IsActive)
    return Task.FromResult(false);

var application = _service.GetApplicationByCode(context.Subject.GetClientId());

context.IsActive = _service.UserHasAccessTo(user, application.Code);

Redirect Loop

Edit

Log file snippet

2016-05-11 18:22:09.0726 user service returned a login result 
2016-05-11 18:22:09.0726 Calling PostAuthenticateAsync on the user service 
2016-05-11 18:22:09.0726 issuing primary signin cookie 
2016-05-11 18:22:09.0726 redirecting to: http://localhost/xpo.security.tokenserver.site/connect/authorize?client_id=security_optimizer&redirect_uri=http:%2F%2Flocalhost%2Fxpo.security.optimizer%2F&response_mode=form_post&response_type=id_token&scope=openid email name roles&state=jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk&nonce=635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm&acr_values=client:security_optimizer impersonate:ctest 
2016-05-11 18:22:09.0726 Start authorize request 
2016-05-11 18:22:09.0726 Start authorize request protocol validation 
2016-05-11 18:22:09.0726 Authorize request validation success
 {
  "ClientId": "security_optimizer",
  "ClientName": "Security Optimizer",
  "RedirectUri": "http://localhost/xpo.security.optimizer/",
  "AllowedRedirectUris": [
    "http://localhost/xpo.security.optimizer/"
  ],
  "SubjectId": "ctest",
  "ResponseType": "id_token",
  "ResponseMode": "form_post",
  "Flow": "Implicit",
  "RequestedScopes": "openid email name roles",
  "State": "jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk",
  "Nonce": "635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm",
  "AuthenticationContextReferenceClasses": [
    "client:security_optimizer",
    "impersonate:ctest"
  ],
  "SessionId": "6f50b19f825f63426a7876c8c2d058df",
  "Raw": {
    "client_id": "security_optimizer",
    "redirect_uri": "http://localhost/xpo.security.optimizer/",
    "response_mode": "form_post",
    "response_type": "id_token",
    "scope": "openid email name roles",
    "state": "jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk",
    "nonce": "635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm",
    "acr_values": "client:security_optimizer impersonate:ctest"
  }
} 
2016-05-11 18:22:09.3603 User is not active. Redirecting to login. 
2016-05-11 18:22:09.3603 End authorize request 
2016-05-11 18:22:09.3603 Redirecting to login page 
2016-05-11 18:22:09.3703 Login page requested 
2016-05-11 18:22:09.7432 user service returned a login result 
2016-05-11 18:22:09.7432 Calling PostAuthenticateAsync on the user service 
2016-05-11 18:22:09.7432 issuing primary signin cookie 
2016-05-11 18:22:09.7432 redirecting to: http://localhost/xpo.security.tokenserver.site/connect/authorize?client_id=security_optimizer&redirect_uri=http:%2F%2Flocalhost%2Fxpo.security.optimizer%2F&response_mode=form_post&response_type=id_token&scope=openid email name roles&state=jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk&nonce=635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm&acr_values=client:security_optimizer impersonate:ctest 
2016-05-11 18:22:09.7527 Start authorize request 
2016-05-11 18:22:09.7527 Start authorize request protocol validation 
2016-05-11 18:22:09.7527 Authorize request validation success
 {
  "ClientId": "security_optimizer",
  "ClientName": "Security Optimizer",
  "RedirectUri": "http://localhost/xpo.security.optimizer/",
  "AllowedRedirectUris": [
    "http://localhost/xpo.security.optimizer/"
  ],
  "SubjectId": "ctest",
  "ResponseType": "id_token",
  "ResponseMode": "form_post",
  "Flow": "Implicit",
  "RequestedScopes": "openid email name roles",
  "State": "jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk",
  "Nonce": "635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm",
  "AuthenticationContextReferenceClasses": [
    "client:security_optimizer",
    "impersonate:ctest"
  ],
  "SessionId": "fec184ed6b9d5eae0c84d36d22c59c1a",
  "Raw": {
    "client_id": "security_optimizer",
    "redirect_uri": "http://localhost/xpo.security.optimizer/",
    "response_mode": "form_post",
    "response_type": "id_token",
    "scope": "openid email name roles",
    "state": "jXGforulK3bJWQs1aK5ML21s67HOcmaCX4lSpS19RWNQtaOHI98cY_lgk2KhKwGT67wyG_EdQU_HIgQe-bAGSEoFhwp5AqtQxswt3fgFMpTzsxOp12p5YbykbNhWqjacUEmZXOepBvC7hEkOiho1VcCoinZlJklCcLMGV5EOuLk",
    "nonce": "635986021053957554.MGJhYjQ4MDQtNDg4My00OTZhLWJjNzItMjJlZDNlZjNhZDg1ZmE5NjM2ZGMtOTBiNy00OTlhLTk0NTItN2E0OTQ5NzM0MjZm",
    "acr_values": "client:security_optimizer impersonate:ctest"
  }
} 
2016-05-11 18:22:10.4456 User is not active. Redirecting to login. 
2016-05-11 18:22:10.4456 End authorize request 
2016-05-11 18:22:10.4475 Redirecting to login page 
2016-05-11 18:22:10.4475 Login page requested 
Culmiferous answered 4/5, 2016 at 1:59 Comment(5)
I had a problem where I was getting a redirect loop after they user signs up, I think is not same issue as you are having but mine was because Id server was redirecting to a non https route in my web appVelites
What do the logs say?Indigestion
@BrockAllen I've edited the question with log snippet. I have a string of these repeating as I hit redirect loop.Culmiferous
Seems that when going to the authorization endpoint that the current user is being rejected from IsActive. At this point all I can suggest is to debug more into IsActive.Indigestion
IsActive returns false when I get into the redirect loop. When IsActive returns true, all is good. What is expected behavior when IsActive needs to return false? Should the request be redirected to some Unauthorized view?Culmiferous

© 2022 - 2024 — McMap. All rights reserved.