Skip to content
This repository has been archived by the owner on Dec 13, 2022. It is now read-only.

State on URL is too long for Azure AD #407

Closed
rposener opened this issue Oct 14, 2016 · 2 comments
Closed

State on URL is too long for Azure AD #407

rposener opened this issue Oct 14, 2016 · 2 comments

Comments

@rposener
Copy link

rposener commented Oct 14, 2016

When using Azure AD as a federated provider, the state querystring is too long to return with the claims. It does seem to be an issue more on Azure's side, but is there an easy way to make the state shorter? this is the config I'm using in Startup.cs on the IdentityServer in QuickStart4_ExternalAuthentication. Google works fine, but adding this for Azure AD fails:

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions { DisplayName = "Azure AD", SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme, SignOutScheme = IdentityServerConstants.SignoutScheme, ClientId = "XXXXXXXXXXXXXXXXXXXXXXXXXXX", ClientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXX", Authority = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}{1}", "common", "/v2.0"), ResponseType = OpenIdConnectResponseType.IdToken, PostLogoutRedirectUri = "https://localhost:44326/", Events = new OpenIdConnectEvents { OnRemoteFailure = OnAuthenticationFailed, } });

the same config works fine in a plain MVC app. Also, if I remove the state from the URL, Azure AD finishes the auth and redirects me back without issue. But of course IdentityServer can't process it without a state parameter.

@rposener
Copy link
Author

For anyone else finding this issue, I found the resolution from another user's fork of the repository. Basically, you need to cache the state, and provide a different State Format.

In Startup.cs do this:
` var dataProtectionProvider = app.ApplicationServices.GetRequiredService();
var distributedCache = app.ApplicationServices.GetRequiredService();

        var dataProtector = dataProtectionProvider.CreateProtector(
            typeof(OpenIdConnectMiddleware).FullName,
            typeof(string).FullName, schemeName,
            "v1");

        var dataFormat = new CachedPropertiesDataFormat(distributedCache, dataProtector);`

then in OpenIdConnectOptions set the property StateDataFormat = dataFormat

here is the code for the CachedPropertiesDataFormat class
`using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.Caching.Distributed;

namespace QuickstartIdentityServer.Authentication
{
///

/// Custom secure data format intended for use with OpenIdConnectMiddleware.
/// It is intended to reduce the size of the state parameter generated
/// by the default PropertiesDataFormat, which results in query strings
/// that are too long for Azure AD to handle.
/// </summary>


public class CachedPropertiesDataFormat
    : ISecureDataFormat<AuthenticationProperties>
{
    public const string CacheKeyPrefix = "CachedPropertiesData-";

    private readonly IDistributedCache _cache;
    private readonly IDataProtector _dataProtector;
    private readonly IDataSerializer<AuthenticationProperties> _serializer;

    public CachedPropertiesDataFormat(
        IDistributedCache cache,
        IDataProtector dataProtector)
        : this(cache, dataProtector, new PropertiesSerializer())
    {

    }

    public CachedPropertiesDataFormat(
        IDistributedCache cache,
        IDataProtector dataProtector,
        IDataSerializer<AuthenticationProperties> serializer)
    {
        _dataProtector = dataProtector;
        _cache = cache;
        _serializer = serializer;
    }

    public string Protect(AuthenticationProperties data)
    {
        return Protect(data, null);
    }

    public string Protect(AuthenticationProperties data, string purpose)
    {
        var key = Guid.NewGuid().ToString();
        var cacheKey = $"{CacheKeyPrefix}{key}";
        var serialized = _serializer.Serialize(data);

        // Rather than encrypt the full AuthenticationProperties
        // cache the data and encrypt the key that points to the data
        _cache.Set(cacheKey, serialized);

        return _dataProtector.Protect(key);
    }

    public AuthenticationProperties Unprotect(string protectedText)
    {
        return Unprotect(protectedText, null);
    }

    public AuthenticationProperties Unprotect(string protectedText, string purpose)
    {
        // Decrypt the key and retrieve the data from the cache.
        var key = _dataProtector.Unprotect(protectedText);
        var cacheKey = $"{CacheKeyPrefix}{key}";
        var serialized = _cache.Get(cacheKey);

        return _serializer.Deserialize(serialized);
    }

}

}`

@lock
Copy link

lock bot commented Jan 15, 2020

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.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant