IBM Security Verify

  • 1.  Protect dotnet Core webapi with OAuth Introspection

    Posted Tue October 19, 2021 04:57 PM
    Hi Guys,

    I am trying to build a bespoke DotNet Core web API protected by ISVaaS, using OAuth introspection.

    I've had problems getting the native reference token validation feature in C# to work (click here). This uses the built-in open-source IdenityServer middleware that comes with DotNet Core. Basically, I'm always getting a 401 UNAUTHORIZED response from the DotNet web API, even though the bearer token I'm passing is valid. Below is the request I am attempting:

    var client = new RestClient("https://localhost:5001/WeatherForecast");
    var request = new RestRequest(Method.GET);
    request.AddHeader("Authorization", "Bearer **REMOVED**");;
    IRestResponse response = client.Execute(request);​

    Below is the response I am getting from the DotNet Core web API:

    < HTTP/1.1 401 Unauthorized
    < Date: Tue, 19 Oct 2021 20:35:35 GMT
    < Server: Kestrel
    < Content-Length: 0​


    The API C# is as follows:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    
    namespace API.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class WeatherForecastController : ControllerBase
        {
            private static readonly string[] Summaries = new[]
            {
                "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
            };
    
            private readonly ILogger<WeatherForecastController> _logger;
    
            public WeatherForecastController(ILogger<WeatherForecastController> logger)
            {
                _logger = logger;
            }
    
            [HttpGet]
            [Authorize]
            public IEnumerable<WeatherForecast> Get()
            {
                
    
                var rng = new Random();
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary = Summaries[rng.Next(Summaries.Length)]
                })
                .ToArray();
            }
        }
    }
    

    Given how popular DotNet Core is, I wanted to reach out to the ISV community to see if anyone had any experience using ISV with homebuilt DotNet Core APIs. 



    ------------------------------
    Timothy
    ------------------------------


  • 2.  RE: Protect dotnet Core webapi with OAuth Introspection

    Posted Wed October 20, 2021 05:42 AM
    Hi Timothy,

    I'm certainly no expert in C# or the Microsoft stack but I'm wondering what options you're passing when initialising the Authorization class.

    I think you would need to pass in the introspection endpoint (NOT the authority since that might assume endpoint path that is incorrect) and also the client_id and client_secret of an API client registered in Verify.  It looks like different authentication schemes are supported for calling the Introspection endpoint - I would suggest using Basic Authentication or passing client_id and client_secret parameters in request body.

    It looks like the Authorization class has logging available - it would be helpful to know what the log output is - that might make it much clearer what is going wrong.

    Jon.

    ------------------------------
    Jon Harry
    Consulting IT Security Specialist
    IBM
    ------------------------------



  • 3.  RE: Protect dotnet Core webapi with OAuth Introspection

    Posted Fri October 22, 2021 01:16 PM
    Edited by Timothy Dilbert Fri October 22, 2021 06:23 PM
    Hi Everyone,

    I was able to figure out the issue. It is C#-related. You need to add app.UseAuthentication(); to the Configure() method in Startup.cs.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseMiddleware<MyMiddleware>();
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }​

    Pretty silly this is left out of the IdentityServer4 documentation. :p



    ------------------------------
    Timothy
    ------------------------------



  • 4.  RE: Protect dotnet Core webapi with OAuth Introspection
    Best Answer

    Posted Fri October 22, 2021 06:41 PM
    Edited by Timothy Dilbert Fri October 22, 2021 10:06 PM
    If anyone else runs into this, below is the full process to get ISV working with a dotNet core web API:

    1. Create a new dotnet core web API (i.e. dotnet new webapi).
    2. Add the IdentityModel.AspNetCore.OAuth2Introspection library (click here).
    3. Within Startups.cs add the following:
      services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme)
              .AddOAuth2Introspection(options =>
               {
                   options.ClientId = "xxx-xxxx-xxxx-xxxxxx";
                   options.ClientSecret = "xxxxxxx";
                   options.IntrospectionEndpoint = "https://demo.verify.ibm.com/v1.0/endpoint/default/introspect"
                  });​



    4. If you want use scopes within your API. Define different policies, and assign them to the scopes you assign the API client in ISV. Below is an example of a Polcy named Read which is assigned if the bearer token has scope API:Read.

      services.AddAuthorization(options => 
      {
          options.AddPolicy("Read", policy => policy.RequireClaim("scope", "API:Read"));
      });​


    5. Within the Configure() method, add app.UseAuthentication(); and app.UseAuthorization();. 

    6. On each endpoint you want to protect, add the [Authorize] tag, and specify the Policies you defined under Step 4. For example, if token as scope API:Read then it has policy Read which means it is authorised to use the endpoint defined below.

      [HttpGet]
      [Authorize(Policy = "Read")]
      public ActionResult Get()
      {
          return Ok();
      }​


    ------------------------------
    Timothy
    ------------------------------