0

I'm working on a project which has angular as Frontend and backend API in asp.net WebAPI. There is an OpenId connect server(mitreid) which is hosted and I have to use that server for authentication and authorization.

I am trying to configure OpenId Connect server authentication to .net WebAPI, this is what I've done in StartUp.cs of WebAPI

app.SetDefaultSignInAsAuthenticationType("OpenIdConnect");
app.UseOpenIdConnectAuthentication(
               new OpenIdConnectAuthenticationOptions
               {
                   ClientId = "some_client",
                   ClientSecret = "some_secret",
                   Authority = "http://localhost:8181/openid-connect-server-webapp",                      
                   UseTokenLifetime = true,
                   ResponseType = "code",
                   Scope = "openid email",
                   SignInAsAuthenticationType = "OpenIdConnect",
                   TokenValidationParameters = new TokenValidationParameters
                   {
                       ValidateIssuer = false,
                       ValidateAudience = false
                   },
                   Notifications = new OpenIdConnectAuthenticationNotifications()
                   {
                       AuthorizationCodeReceived = (context) =>
                       {
                           var code = context.Code;
                           return Task.FromResult(0);
                       },
                       RedirectToIdentityProvider = async n =>                       
                       {
                           n.ProtocolMessage.RedirectUri = "http://localhost:54464/";
                           n.OwinContext.Authentication.Challenge(new String[] { "OpenIdConnect" });
                       },
                       SecurityTokenValidated = (n) =>
                       {
                           var nid = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType, "user", "user");                                  
                           nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
                           nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));    
                           nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));
                           nid.AddClaim(new Claim("app_specific", "some data"));
                           n.AuthenticationTicket = new AuthenticationTicket(nid, n.AuthenticationTicket.Properties);
                           return Task.FromResult(0);
                       },
                       SecurityTokenReceived = (context) =>
                       {
                           var code = context;    
                           return Task.FromResult(0);
                       },
                       AuthenticationFailed = (context) =>
                       { 
                           //some redirect
                           context.HandleResponse(); 
                           return Task.FromResult(0);
                       }
                   }
               });

I tried setting configuration even, like below

ConfigurationManager = 
new ConfigurationManager<OpenIdConnectConfiguration>
    ("http://localhost:8181/openid-connect-server-webapp/.well-known/openid-configuration"),
Configuration = new OpenIdConnectConfiguration
{
    Issuer = "http://localhost:8181/openid-connect-server-webapp",
    AuthorizationEndpoint = "http://localhost:8181/openid-connect-server-webapp/authorize",
    TokenEndpoint = "http://localhost:8181/openid-connect-server-webapp/token",
    UserInfoEndpoint = "http://localhost:8181/openid-connect-server-webapp/userinfo"
},

When I try to debug the API (at port 54464), I put authorize attr on a controller, it is redirecting to the OpenID login page and then after successful login and then no controller action is being executed. let's say this is the API call I'm testing http://localhost:54464/api/common/getlist initially for first call API redirects to the login page and then redirecting to http://localhost:54464/api/common/getlist/?code=V7KFPZ&state=OpenIdConnect.AuthenticationProperties%3D****somecode**** instead of returning a JSON array.

I tried generating Bearer token using code from above-redirected URL from postman which was successful. however, when tried to use the token in the authorization header using postman, the response is OpenID login HTML page.

The issue none of the notification events are executing other than RedirectToIdentityProvider

I know I'm missing something, please point me those, I'm fairly new to this. let me know if I'm doing something wrong, some configuration mistakes, or any solutions implementing OpenId client.

NikhilGoud
  • 574
  • 1
  • 5
  • 21
  • You are using the authorization code flow. I suppose your Angular application is a stand-alone SPA and not even hosted on under the same hostname and port as your WebAPI app. For scenarios like this there is the Implicit Flow. The Angular application will take care of login itself and obtains an ID and Access Token. It will then send the Access Token to the API to obtain the resources. I use `oidc-client` (NPM) as a client library and `IdentityServer3.AccessTokenValidation` (NuGet) for the api. If you want to go in this direction let me know and I will provide an answer. – mode777 Dec 28 '17 at 15:11
  • Yes, could you please provide some insights on this approach. – NikhilGoud Dec 29 '17 at 10:26

1 Answers1

1

As stated in the comment above, the Authorization Code flow is not very suitable for Javascript clients such as Angular applications. Therefore this describes a possible setup for the Implicit Flow

This is how you could approach it with popular libraries:

Authorization Server (Mitreid): I don't know anything about Mitreid but you have to register your client application with ID some_client or change your existing client configuration to use the implict flow. Some implementations like Identity Server will need an additional parameter to allow access tokens to be passed to the browser. Aslo make sure you register the http://YOUR_ANGULAR_APP/auth-callback as a redirect URI. You also might want to register a scope for your WebApi app, so that it can consume access tokens. I'll assume you have a scope called webapi. I'll also assume that you'll use JWT's and not reference tokens. In the later case the WebAPI configuration is slightly different.

Client (Angular): I recommend the oidc-client library you can install via NPM. Here's a tutorial how to integrate it into Angular: https://www.scottbrady91.com/Angular/SPA-Authentiction-using-OpenID-Connect-Angular-CLI-and-oidc-client. I updated the settings according to your examples:

export function getClientSettings(): UserManagerSettings {
    return {
        authority: 'http://localhost:8181/openid-connect-server-webapp',
        client_id: 'some_client',
        redirect_uri: 'http://YOUR_ANGULAR_APP/auth-callback',
        post_logout_redirect_uri: 'http://YOUR_ANGULAR_APP/',
        response_type:"id_token token",
        scope:"openid email webapi",
        filterProtocolClaims: true,
        loadUserInfo: true
   };
}

The Angular App will initiate the login procedure which leaves you with an ID Token and an Access Token if everything worked correctly. oidc-client also prepares an Authorization header with the Access Token which you have to add to all authorized requests to your WebAPI app. oidc-client will also automatically load user claims.

Resource Server (WebAPI App): The WebAPI side implementation is quite simple as you just have to add access token validation middleware and [Authorize] attributes. For pre-ASP.NET Core apps I like to use IdentityServer3.AccessTokenValidation, which you can install via Nuget.

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
        {
            Authority = "http://localhost:8181/openid-connect-server-webapp",
            RequiredScopes = "openid email webapi"
        });

If you add an [Authorize] endpoint to your WebAPI you should get a ClaimsIdentity as User based on the claims contained in the JWT.

mode777
  • 3,037
  • 2
  • 23
  • 34
  • I'll try this and get back. The issue is the openId server did not implement token response type. So, we have to validate the token manually – NikhilGoud Jan 02 '18 at 08:05