Skip to content
This repository has been archived by the owner on Jul 31, 2024. It is now read-only.

Fix custom redirect after ProcessLogin for custom authorize response generators #4615

Merged
merged 3 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,24 @@ public virtual async Task<InteractionResponse> ProcessInteractionAsync(Validated
}

var result = await ProcessLoginAsync(request);

if (!result.IsLogin && !result.IsError && !result.IsRedirect)
{
result = await ProcessConsentAsync(request, consent);
}

if (result.IsLogin && request.PromptModes.Contains(OidcConstants.PromptModes.None))
if ((result.IsLogin || result.IsConsent || result.IsRedirect) && request.PromptModes.Contains(OidcConstants.PromptModes.None))
{
// prompt=none means do not show the UI
Logger.LogInformation("Changing response to LoginRequired: prompt=none was requested");
result = new InteractionResponse
{
Error = OidcConstants.AuthorizeErrors.LoginRequired
Error = result.IsLogin ? OidcConstants.AuthorizeErrors.LoginRequired :
result.IsConsent ? OidcConstants.AuthorizeErrors.ConsentRequired :
OidcConstants.AuthorizeErrors.InteractionRequired
};
}

if (result.IsLogin || result.IsError)
{
return result;
}

result = await ProcessConsentAsync(request, consent);

return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Threading.Tasks;
using FluentAssertions;
using IdentityModel;
using IdentityServer.UnitTests.Common;
using IdentityServer4;
using IdentityServer4.Configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using System.Threading.Tasks;
using FluentAssertions;
using IdentityServer.UnitTests.Common;
using IdentityServer4;
using IdentityServer4.Configuration;
using IdentityServer4.Models;
using IdentityServer4.ResponseHandling;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Xunit;
using static IdentityModel.OidcConstants;

namespace IdentityServer.UnitTests.ResponseHandling.AuthorizeInteractionResponseGenerator
{
public class CustomAuthorizeInteractionResponseGenerator : IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator
{
public CustomAuthorizeInteractionResponseGenerator(ISystemClock clock, ILogger<IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator> logger, IConsentService consent, IProfileService profile) : base(clock, logger, consent, profile)
{
}

public InteractionResponse ProcessLoginResponse { get; set; }
protected internal override Task<InteractionResponse> ProcessLoginAsync(ValidatedAuthorizeRequest request)
{
if (ProcessLoginResponse != null)
{
return Task.FromResult(ProcessLoginResponse);
}

return base.ProcessLoginAsync(request);
}

public InteractionResponse ProcessConsentResponse { get; set; }
protected internal override Task<InteractionResponse> ProcessConsentAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
{
if (ProcessConsentResponse != null)
{
return Task.FromResult(ProcessConsentResponse);
}
return base.ProcessConsentAsync(request, consent);
}
}

public class AuthorizeInteractionResponseGeneratorTests_Custom
{
private IdentityServerOptions _options = new IdentityServerOptions();
private CustomAuthorizeInteractionResponseGenerator _subject;
private MockConsentService _mockConsentService = new MockConsentService();
private StubClock _clock = new StubClock();

public AuthorizeInteractionResponseGeneratorTests_Custom()
{
_subject = new CustomAuthorizeInteractionResponseGenerator(
_clock,
TestLogger.Create<IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator>(),
_mockConsentService,
new MockProfileService());
}


[Fact]
public async Task ProcessInteractionAsync_with_overridden_login_returns_redirect_should_return_redirect()
{
var request = new ValidatedAuthorizeRequest
{
ClientId = "foo",
Subject = new IdentityServerUser("123")
{
IdentityProvider = IdentityServerConstants.LocalIdentityProvider
}.CreatePrincipal(),
Client = new Client
{
},
};

_subject.ProcessLoginResponse = new InteractionResponse
{
RedirectUrl = "/custom"
};

var result = await _subject.ProcessInteractionAsync(request);

result.IsRedirect.Should().BeTrue();
result.RedirectUrl.Should().Be("/custom");
}

[Fact]
public async Task ProcessInteractionAsync_with_prompt_none_and_login_returns_login_should_return_error()
{
var request = new ValidatedAuthorizeRequest
{
ClientId = "foo",
Subject = new IdentityServerUser("123")
{
IdentityProvider = IdentityServerConstants.LocalIdentityProvider
}.CreatePrincipal(),
Client = new Client
{
},
PromptModes = new[] { PromptModes.None },
};

_subject.ProcessLoginResponse = new InteractionResponse
{
IsLogin = true
};

var result = await _subject.ProcessInteractionAsync(request);

result.IsError.Should().BeTrue();
result.Error.Should().Be("login_required");
}

[Fact]
public async Task ProcessInteractionAsync_with_prompt_none_and_login_returns_redirect_should_return_error()
{
var request = new ValidatedAuthorizeRequest
{
ClientId = "foo",
Subject = new IdentityServerUser("123")
{
IdentityProvider = IdentityServerConstants.LocalIdentityProvider
}.CreatePrincipal(),
Client = new Client
{
},
PromptModes = new[] { PromptModes.None },
};

_subject.ProcessLoginResponse = new InteractionResponse
{
RedirectUrl = "/custom"
};

var result = await _subject.ProcessInteractionAsync(request);

result.IsError.Should().BeTrue();
result.Error.Should().Be("interaction_required");
result.RedirectUrl.Should().BeNull();
}

[Fact]
public async Task ProcessInteractionAsync_with_prompt_none_and_consent_returns_consent_should_return_error()
{
var request = new ValidatedAuthorizeRequest
{
ClientId = "foo",
Subject = new IdentityServerUser("123")
{
IdentityProvider = IdentityServerConstants.LocalIdentityProvider
}.CreatePrincipal(),
Client = new Client
{
},
PromptModes = new[] { PromptModes.None },
};

_subject.ProcessConsentResponse = new InteractionResponse
{
IsConsent = true
};

var result = await _subject.ProcessInteractionAsync(request);

result.IsError.Should().BeTrue();
result.Error.Should().Be("consent_required");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.Text.Json;
using System.Threading.Tasks;
using FluentAssertions;
using IdentityModel;
using IdentityServer.UnitTests.Common;
using IdentityServer4;
using IdentityServer4.Models;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using IdentityServer4.Validation;
using Xunit;

namespace IdentityServer.UnitTests.Validation
Expand Down