2

I am using IdentityServer4 to get my OpenId tokens for my web app. But my web app uses Owin for security. I cannot find any example samples of where this is done.

So this code works; In my client;

using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using SIR.API.Caller.Helpers;

namespace SIR.API.Caller
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = Settings.SignInAsAuthenticationType    // "Cookies";
            });

            app.UseOpenIdConnectAuthentication(openIdConnectOptions: new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = "oidc",
                Authority = Settings.AuthorityUrl1,      //ID Server,  "https://localhost:44314/"; https://localhost:44307/
                ClientId = Settings.ClientId,           // "SIR"
                Scope = Settings.Scope,                 // "openid profile";
                ResponseType = Settings.ResponseType,   // "id_token code";
                SignInAsAuthenticationType = Settings.SignInAsAuthenticationType,
                //--------------------------------------// "Cookies";
                RedirectUri = Settings.RedirectUri,     // URL of website, http://localhost:50000/signin-oidc;
                //RedirectUri = Settings.RedirectUri1,     // URL of website, http://localhost:53200/signin-oidc;
                RequireHttpsMetadata = Settings.RequireHttpsMetadata,
                //--------------------------------------// true
                ClientSecret = "secret"
            });

            app.Use(async (ctx, next) =>
            {
                var message = ctx.Authentication.User.Identity.IsAuthenticated
                    ? $"User: {ctx.Authentication.User.Identity.Name}"
                    : "User Not Authenticated";
                await next();
            });
        }
    }
}

In my ID 4 server the startup is;

using System.Security.Cryptography.X509Certificates;
using IdentityServer4;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Mulalley.IdentityServer4.Helpers;
using QuickstartIdentityServer;

namespace Mulalley.IdentityServer4
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            // configure identity server with in-memory stores, keys, clients and scopes
            services.AddIdentityServer()
                //.AddDeveloperSigningCredential()
                .AddSigningCredential(new X509Certificate2(Settings.CertPath, Settings.Password))
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetUsers());

            services.AddAuthentication()
                .AddGoogle("Google", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    // register your IdentityServer with Google at https://console.developers.google.com
                    // enable the Google+ API
                    // set the redirect URI to http://localhost:port/signin-google
                    options.ClientId = "copy client ID from Google here";
                    options.ClientSecret = "copy client secret from Google here";
                })
                .AddOpenIdConnect("oidc", "OpenID Connect", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.SignOutScheme = IdentityServerConstants.SignoutScheme;

                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";

                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role"
                    };
                });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

and the Config.cs is;

using IdentityServer4;
using IdentityServer4.Models;
using IdentityServer4.Test;
using System.Collections.Generic;
using System.Security.Claims;

namespace QuickstartIdentityServer
{
    public class Config
    {
        // scopes define the resources in your system
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };
        }

        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("SIR", "Service Inspection Report")
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            var baseUri = "http://localhost:53200/";
            // client credentials client
            return new List<Client>
            {
                new Client
                {
                    ClientId = "client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "SIR" },
                    AlwaysIncludeUserClaimsInIdToken = true
                },

                // resource owner password grant client
                new Client
                {
                    ClientId = "ro.client",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "SIR" },
                    AlwaysIncludeUserClaimsInIdToken = true
                },

                // OpenID Connect hybrid flow and client credentials client (MVC)
                new Client
                {
                    ClientId = "SIR",
                    ClientName = "SIR",
                    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },

                    RedirectUris = { baseUri + "signin-oidc" },
                    PostLogoutRedirectUris = { baseUri + "signout-callback-oidc" },

                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "SIR"
                    },
                    AllowOfflineAccess = true,
                    AlwaysIncludeUserClaimsInIdToken = true
                }
            };
        }

        public static List<TestUser> GetUsers()
        {
            return new List<TestUser>
            {
                new TestUser
                {
                    SubjectId = "1",
                    Username = "alice",
                    Password = "password",

                    Claims = new List<Claim>
                    {
                        new Claim("name", "Alice"),
                        new Claim("website", "https://alice.com")
                    }
                },
                new TestUser
                {
                    SubjectId = "2",
                    Username = "bob",
                    Password = "password",

                    Claims = new List<Claim>
                    {
                        new Claim("name", "Bob"),
                        new Claim("website", "https://bob.com")
                    }
                }
            };
        }
    }
}

And the question is how do I get the token in C# so I can have a look at it? And how do I set the GetClaimsFromUserInfoEndpoint = true which is not available in OWIN? Are there any code samples I can look at with OWIN access to ID4?

EDIT: This code appears to be what I need: https://identitymodel.readthedocs.io/en/latest/client/token.html

However I put the code in and I get an access token which when I put it in jwt.io I get a message "Invalid Signature".

       private static async Task<TokenResponse> GetClientCredentialsTokenResponse()
        {
            var client = new HttpClient();
            var tokenRequest = new ClientCredentialsTokenRequest
            {
                Address = Settings.AuthorityUrl1 + "connect/token",
                ClientId = Settings.ClientId,
                ClientSecret = "secret",
                Scope = "SIR"
            };

            return await client.RequestClientCredentialsTokenAsync(tokenRequest);
        }

        private static async Task<TokenResponse> GetTokenResponse()
        {
            var client = new HttpClient();
            var tokenRequest = new TokenRequest
            {
                Address = Settings.AuthorityUrl1 + "connect/token",
                GrantType = GrantType.ClientCredentials,

                ClientId = Settings.ClientId,
                ClientSecret = "secret",

                Parameters =
                {
                    {"scope", "SIR"}
                }
            };

            return await client.RequestTokenAsync(tokenRequest);
        }

        private static void ThrowResponseException(TokenResponse response)
        {
            const string message = "Problem accessing the UserInfo endpoint";
            if (response.Exception == null)
            {
                throw new Exception($"{message}: {response.Error}. {response.ErrorDescription}.");
            }

            throw new Exception(message, response.Exception);
        }
    }
}
arame3333
  • 9,887
  • 26
  • 122
  • 205
  • Does this work or what's happening? I can see a few things might be out of place. Also, there is no in built claims retrieval from user info in the OWIN middleware so you either build your own or use the easier option and set `AlwaysIncludeClaimsInIdToken` to true in Identity server client setup. – Vidmantas Blazevicius Jan 08 '19 at 10:40
  • Yes I have set AlwaysIncludeClaimsInIdToken to true in the config class copied here. I was hoping there was a better way of doing it but I guess not. I know there is in .Net Core. I would like to know how to retreive the token value so I can inspect that to display on the console. – arame3333 Jan 08 '19 at 11:40
  • Apart from that it is working. I am learning from sample code in .Net Core so it is hard to work out how the same can be done in Owin. – arame3333 Jan 08 '19 at 11:44
  • 1
    No problems, I'll added you an example of how to get the raw `access_token` value that you can then use somewhere like https://jwt.io to decode and inspect. I was more wondering if you get the user authenticated with your current version. I can feel you about trying to make idsrv4 work on with .Net client - I had some frustrations myself. – Vidmantas Blazevicius Jan 08 '19 at 11:49

0 Answers0