Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can ServiceStack.Authentication.IdentityServer be used with IdentityServer4? #2

Closed
murraywsmith opened this issue Jan 13, 2017 · 5 comments
Assignees
Labels

Comments

@murraywsmith
Copy link

I'm trying to use ServiceStack.Authentication.IdentityServer with IdentityServer4 and I'm getting an error validating an access token. Just wondering if I can expect the plugin to work with IdentityServer4?

@wwwlicious
Copy link
Owner

wwwlicious commented Jan 13, 2017

Hi Murray, thanks for letting us know about your issue.
The short answer is yes, we have a plugin version for IdentityServer4.

The longer answer is that we haven't yet completed the update for the changes in the v1.x release late Dec.
We will look to update the nuget package soon and have already completed some of the work.

In the meantime, if you can supply the error details/stacktrace and any additional information like servicestack and identityserver exact versions that might help us as we update the plugin, that would be appreciated.

@murraywsmith
Copy link
Author

Thanks for the quick reply. The information on my system can be found below.

Regarding the upcoming update to the nugget package, I have a few questions:

  • Will the plugin continue to work with ServiceStack 4.0.56 or will I need to upgrade to the latest version of ServiceStack?
  • Do you have a ballpark idea when the updated nugget package will be available? No commitments needed obviously since this is an open source project. I'm just trying to get an idea whether you are thinking it will likely be a week, a month, or longer?

Here's the information on my system:

  • ServiceStack 4.0.56 in my WebApp.

  • IdentityServer is an ASP.NET Core web application using IdentityServer4 1.0.0 (the one released at the end of Dec 2016).

  • My web app is a hello world application. It has one api service (hello) protected by the [Authenticate] attribute. Although once I get [Authenticate] working I will also want to add the [RequiredRole("rolename')] attribute to it as well.

  • When the user navigates to the hello service in the browser, they are redirected to my login page served up by my IdentityServer.

  • during the login, UserAuthProvider.AuthenticateAsync() is called. That results in a call to the IsValidAccessToken(IAuthTokens authTokens) method in IdentityServerAuthProvider. And that eventually results in a call to my IdentityServer's introspection end point.

  • The call to the introspection endpoint ends up making a call to ApiSectretValidator.ValidateAsync(). Inside that call the following lines of code get executed.
    // load API resource
    var api = await _resources.FindApiResourceAsync(parsedSecret.Id);
    if (api == null)
    {
    await RaiseFailureEvent(parsedSecret.Id, "Unknown API resource");

              _logger.LogError("No API resource with that name found. aborting");
              return fail;
          }
    
  • The FindApiResourceAsync() call returns null. When I step through the code in the debugger, I can see that parsedSecret.Id is equal to my ClientId (i.e. it equals "mvc". See my config code for my IdentityServer and the plugin in my WebApp below.). That will always fail to find an api resource because it should be using an api resource name not a client id to find the api resource. So I'm not sure how I got to the point where a client id is being used to search for a resource. (FindApiResourceAsync() is comparing the search value against resource names.) It could be I just don't have things configured correctly?

Here's my configuration on the IdentityServer side:

public class Config
{
    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new IdentityResource {
                Name = "role",
                UserClaims = new List<string> {
                    JwtClaimTypes.Role 
                    },
            }
        };
    }

    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource
            {
                Name = "api1",
                UserClaims = new List<string>
                {
                    JwtClaimTypes.Role,
                    JwtClaimTypes.Name
                }
            },
            new ApiResource
            {
                Name = "helloapiresource",
                UserClaims = new List<string>
                {
                    JwtClaimTypes.Role,
                    JwtClaimTypes.Name
                },
                Scopes = new List<Scope>
                {
                    new Scope("helloapiscope", "Scope for Hello api service.")
                }
            }
        };
    }

    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "mvc",
                ClientName = "MVC Hybrid Client",
                AllowedGrantTypes = GrantTypes.Hybrid,
                RedirectUris = {"http://localhost:5002/signin-oidc", "http://localhost:33952/auth/IdentityServer", "http://localhost:33952/hello" },
                PostLogoutRedirectUris = {"http://localhost:5002" },
                ClientSecrets = new List<Secret>
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "role",
                    "helloapiscope"
                },
                RequireConsent = false,
                AlwaysSendClientClaims = true,
                AccessTokenType = AccessTokenType.Jwt,
                AccessTokenLifetime = 120,
                UpdateAccessTokenClaimsOnRefresh = true,
                RefreshTokenUsage = TokenUsage.ReUse,
                RefreshTokenExpiration = TokenExpiration.Sliding,
                SlidingRefreshTokenLifetime = 120,  // 2 minutes
            }
        };
    }

And this is what my configuration for the plugin looks like in AppHost.cs in my WebApp.

public override void Configure(Funq.Container container)
{
SetConfig(new HostConfig
{
WebHostUrl = "http://localhost:33952/"
});

        AppSettings.SetUserAuthProvider()
            .SetAuthRealm("http://localhost:5000")
            .SetClientId("mvc")
            .SetClientSecret("secret")
            .SetScopes("openid profile role helloapiscope");

        Plugins.Add(new IdentityServerAuthFeature());
    }
}

@wwwlicious
Copy link
Owner

Brillliant! Thank you for that info, really helpful and we will look into the details next week. To answer your first two questions.

  1. Yes we endeavour to remain backwards compatible with major releases of servicestack so unless something in the authprovider contracts has changed, we will remain compatible with v4.0.56.

  2. I appreciate your understanding that we cannot make any promises for the updated package timescales but I think it will be between a week and month. I'm hopeful that it will be next week but I don't want to disappoint anyone

@stuartbfs
Copy link
Contributor

Hi Murray,

We've pushed an updated version of the plugin that might resolve the problem with it looking for the client in the ApiResources.

The ApiResource is new in IdentityServer4 so hadn't been an issue previously but the underlying issue was because the plugin was calling the Introspec endpoint to validate the access token. This is something only ApiResources can do in IdentityServer4.

Can you let me know if you have any further problems?

@murraywsmith
Copy link
Author

I downloaded the latest plugin version and confirmed that the problem is resolved. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants