IBM Verify

IBM Verify

Join this online user group to communicate across Security product users and IBM experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.

 View Only
  • 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
    ------------------------------