Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

implementing roles in identity server 4 with asp.net identity

I am working on an asp.net MVC application with identity server 4 as token service. I have an api as well which has some secure resources. I want to implement roles (Authorization) for api. I want to make sure that only an authorized resource with valid role can access an api end point otherwise get 401 (unauthorized error).

Here are my configurations:

Client

         new Client()
            {
                ClientId = "mvcClient",
                ClientName = "MVC Client",                    
                AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

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

                RequireConsent = false;

                // where to redirect to after login
                RedirectUris = { "http://localhost:5002/signin-oidc" },
                // where to redirect to after logout
                PostLogoutRedirectUris = { "http://localhost:5002" },

                AllowedScopes =
                {
                    StandardScopes.OpenId.Name,
                    StandardScopes.Profile.Name,
                    StandardScopes.OfflineAccess.Name,
                    StandardScopes.Roles.Name,
                    "API"
                }
            }

Scopes

 return new List<Scope>()
            {
                StandardScopes.OpenId, // subject id
                StandardScopes.Profile, // first name, last name
                StandardScopes.OfflineAccess,  // requesting refresh tokens for long lived API access
               StandardScopes.Roles,
                new Scope()
                {
                    Name = "API",
                    Description = "API desc",
                     Type = ScopeType.Resource,
                    Emphasize = true,
                    IncludeAllClaimsForUser = true,
                    Claims = new List<ScopeClaim>
                    {
                        new ScopeClaim(ClaimTypes.Name),      
                        new ScopeClaim(ClaimTypes.Role)
                    }
                }
            };

User

new InMemoryUser()
                {
                    Subject = "1",
                    Username = "testuser",
                    Password = "password",
                    Claims = new List<Claim>()
                    {
                        new Claim("name", "Alice"),
                        new Claim("Website", "http://alice.com"),
                         new Claim(JwtClaimTypes.Role, "admin")

                    }
                }

and in server startup i added this:

services.AddIdentityServer() .AddTemporarySigningCredential() .AddSigningCredential(cert) .AddInMemoryClients(Config.GetClients()) .AddInMemoryScopes(Config.GetScopes()) .AddInMemoryUsers(Config.GetUsers())

in api startup, i have this:

  app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions()
            {
                Authority = "http://localhost:5000",
                ScopeName = "NamfusAPI",
                RequireHttpsMetadata = false
            });

in api controller, i have this:

 [Authorize(Roles = "admin")]
        public IActionResult Get()
        {
            return new JsonResult(from c in User.Claims select new {c.Type, c.Value });
        }

in MVC client startup, i have this:

 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

 app.UseCookieAuthentication(new CookieAuthenticationOptions()
            {
                AuthenticationScheme = "Cookies"
            });


            var oidcOptions = new OpenIdConnectOptions()
            {
                AuthenticationScheme = "oidc",
                SignInScheme = "Cookies",

                Authority = "http://localhost:5000",
                RequireHttpsMetadata = false,

                ClientId = "mvcClient",
                ClientSecret = "secret",
                SaveTokens = true,
                GetClaimsFromUserInfoEndpoint = true,
                ResponseType = "code id_token", // hybrid flow

            };


            oidcOptions.Scope.Clear();
            oidcOptions.Scope.Add("openid");
            oidcOptions.Scope.Add("profile");
            oidcOptions.Scope.Add("NamfusAPI");
            oidcOptions.Scope.Add("offline_access");
            oidcOptions.Scope.Add("roles");

I am trying to call the api like this:

public async Task<IActionResult> CallApiUsingUserAccessToken()
        {
            var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

            var client = new HttpClient();
            client.SetBearerToken(accessToken);
            var content = await client.GetStringAsync("http://localhost:5001/identity");

            ViewBag.Json = JArray.Parse(content).ToString();
            return View("json");
        } 

I get access token but when call is made to api (identity/get), I get 302 error Forbidden (in chrome network it shows 500 internal server error). If I change API Authorize attribute from

  [Authorize(Roles = "admin")]
            public IActionResult Get()

to (without role):

 [Authorize]
        public IActionResult Get()

it works and I get data from api in mvc app. How can I apply roles in this code.

Please suggest.

like image 619
Asif Hameed Avatar asked Nov 23 '16 16:11

Asif Hameed


People also ask

How do I add a role to my identity server?

Roles can be created in AdminUI in order to create the roles you need within your application. By clicking "Add Role", we can create a new role within the AdminUI application. Selecting this button will bring up a window to enable you to add a new role.

How does identity work in asp net?

ASP.NET Identity is the membership system for authentication and authorization of the users by building an ASP.NET application. ASP.NET Identity is the membership system for authentication and authorization of the users by building an ASP.NET application.

What is the difference between identity and identity server?

Identity Server is a centralized OAuth/OIDC token server. Identity is an API for managing user accounts. Identity Server might use Identity to manage accounts.


1 Answers

First, you need to request "API" scope in your OpenIdConnectOptions().

oidcOptions.Scope.Add("API");

or

Scope = { "API", "offline_access",..},

Then you need to check if the role claim is included in the claims list available to your API controler(don't apply the roles filter in authorize attribute yet. Put a debug point inside controller method and expand User property). Check if the type of the role claim you received(listed in Claims Collection) matches User.Identity.RoleClaimType property

enter image description here

If the role claim type you have and User.Identity.RoleClaimType doesn't match, authorize attribute with roles filter won't work. You can set the correct RoleClaimType in IdentityServerAuthenticationOptions() like follows

app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
        {
            Authority = "http://localhost:5000",
            ScopeName = "API",
            RoleClaimType = ClaimTypes.Role,
            RequireHttpsMetadata = false
        });
like image 151
rawel Avatar answered Oct 05 '22 08:10

rawel