Skip to content
This repository has been archived by the owner on Jul 31, 2024. It is now read-only.

Commit

Permalink
added events for introspection
Browse files Browse the repository at this point in the history
  • Loading branch information
leastprivilege committed Apr 16, 2018
1 parent 220ab84 commit 4611ac9
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 11 deletions.
18 changes: 14 additions & 4 deletions src/IdentityServer4/Endpoints/IntrospectionEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using IdentityServer4.Endpoints.Results;
using Microsoft.AspNetCore.Http;
using System.Net;
using IdentityServer4.Services;
using IdentityServer4.Events;

namespace IdentityServer4.Endpoints
{
Expand All @@ -20,26 +22,30 @@ namespace IdentityServer4.Endpoints
internal class IntrospectionEndpoint : IEndpointHandler
{
private readonly IIntrospectionResponseGenerator _responseGenerator;
private readonly IEventService _events;
private readonly ILogger _logger;
private readonly IIntrospectionRequestValidator _requestValidator;
private readonly IApiSecretValidator _apiSecretValidator;

/// <summary>
/// Initializes a new instance of the <see cref="IntrospectionEndpoint"/> class.
/// Initializes a new instance of the <see cref="IntrospectionEndpoint" /> class.
/// </summary>
/// <param name="apiSecretValidator">The API secret validator.</param>
/// <param name="requestValidator">The request validator.</param>
/// <param name="responseGenerator">The generator.</param>
/// <param name="events">The events.</param>
/// <param name="logger">The logger.</param>
public IntrospectionEndpoint(
IApiSecretValidator apiSecretValidator,
IIntrospectionRequestValidator requestValidator,
IIntrospectionResponseGenerator responseGenerator,
IApiSecretValidator apiSecretValidator,
IIntrospectionRequestValidator requestValidator,
IIntrospectionResponseGenerator responseGenerator,
IEventService events,
ILogger<IntrospectionEndpoint> logger)
{
_apiSecretValidator = apiSecretValidator;
_requestValidator = requestValidator;
_responseGenerator = responseGenerator;
_events = events;
_logger = logger;
}

Expand Down Expand Up @@ -84,6 +90,8 @@ private async Task<IEndpointResult> ProcessIntrospectionRequestAsync(HttpContext
if (body == null)
{
_logger.LogError("Malformed request body. aborting.");
await _events.RaiseAsync(new TokenIntrospectionFailureEvent(apiResult.Resource.Name, "Malformed request body"));

return new StatusCodeResult(HttpStatusCode.BadRequest);
}

Expand All @@ -93,6 +101,8 @@ private async Task<IEndpointResult> ProcessIntrospectionRequestAsync(HttpContext
if (validationResult.IsError)
{
LogFailure(validationResult.Error, apiResult.Resource.Name);
await _events.RaiseAsync(new TokenIntrospectionFailureEvent(apiResult.Resource.Name, validationResult.Error));

return new BadRequestResult(validationResult.Error);
}

Expand Down
81 changes: 81 additions & 0 deletions src/IdentityServer4/Events/TokenIntrospectionFailureEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityServer4.Extensions;
using System.Collections.Generic;

namespace IdentityServer4.Events
{
/// <summary>
/// Event for failed token introspection
/// </summary>
/// <seealso cref="IdentityServer4.Events.Event" />
public class TokenIntrospectionFailureEvent : Event
{
/// <summary>
/// Initializes a new instance of the <see cref="TokenIntrospectionSuccessEvent" /> class.
/// </summary>
/// <param name="apiName">Name of the API.</param>
/// <param name="errorMessage">The error message.</param>
/// <param name="token">The token.</param>
/// <param name="apiScopes">The API scopes.</param>
/// <param name="tokenScopes">The token scopes.</param>
public TokenIntrospectionFailureEvent(string apiName, string errorMessage, string token = null, IEnumerable<string> apiScopes = null, IEnumerable<string> tokenScopes = null)
: base(EventCategories.Token,
"Token Introspection Failure",
EventTypes.Failure,
EventIds.TokenIntrospectionFailure,
errorMessage)
{
ApiName = apiName;

if (token.IsPresent())
{
Token = Obfuscate(token);
}

if (apiScopes != null)
{
ApiScopes = apiScopes;
}

if (tokenScopes != null)
{
TokenScopes = tokenScopes;
}
}

/// <summary>
/// Gets or sets the name of the API.
/// </summary>
/// <value>
/// The name of the API.
/// </value>
public string ApiName { get; set; }

/// <summary>
/// Gets or sets the token.
/// </summary>
/// <value>
/// The token.
/// </value>
public string Token { get; set; }

/// <summary>
/// Gets or sets the API scopes.
/// </summary>
/// <value>
/// The API scopes.
/// </value>
public IEnumerable<string> ApiScopes { get; set; }

/// <summary>
/// Gets or sets the token scopes.
/// </summary>
/// <value>
/// The token scopes.
/// </value>
public IEnumerable<string> TokenScopes { get; set; }
}
}
83 changes: 83 additions & 0 deletions src/IdentityServer4/Events/TokenIntrospectionSuccessEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityServer4.Extensions;
using IdentityServer4.Validation;
using System.Collections.Generic;
using System.Linq;

namespace IdentityServer4.Events
{
/// <summary>
/// Event for successful token introspection
/// </summary>
/// <seealso cref="IdentityServer4.Events.Event" />
public class TokenIntrospectionSuccessEvent : Event
{
/// <summary>
/// Initializes a new instance of the <see cref="TokenIntrospectionSuccessEvent" /> class.
/// </summary>
/// <param name="result">The result.</param>
public TokenIntrospectionSuccessEvent(IntrospectionRequestValidationResult result)
: base(EventCategories.Token,
"Token Introspection Success",
EventTypes.Success,
EventIds.TokenIntrospectionSuccess)
{
ApiName = result.Api.Name;
IsActive = result.IsActive;

if (result.Token.IsPresent())
{
Token = Obfuscate(result.Token);
}

if (!result.Claims.IsNullOrEmpty())
{
ClaimTypes = result.Claims.Select(c => c.Type).Distinct();
TokenScopes = result.Claims.Where(c => c.Type == "scope").Select(c => c.Value);
}
}

/// <summary>
/// Gets or sets the name of the API.
/// </summary>
/// <value>
/// The name of the API.
/// </value>
public string ApiName { get; set; }

/// <summary>
/// Gets or sets a value indicating whether this instance is active.
/// </summary>
/// <value>
/// <c>true</c> if this instance is active; otherwise, <c>false</c>.
/// </value>
public bool IsActive { get; set; }

/// <summary>
/// Gets or sets the token.
/// </summary>
/// <value>
/// The token.
/// </value>
public string Token { get; set; }

/// <summary>
/// Gets or sets the claim types.
/// </summary>
/// <value>
/// The claim types.
/// </value>
public IEnumerable<string> ClaimTypes { get; set; }

/// <summary>
/// Gets or sets the token scopes.
/// </summary>
/// <value>
/// The token scopes.
/// </value>
public IEnumerable<string> TokenScopes { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityModel;
using IdentityServer4.Events;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
Expand All @@ -18,17 +20,27 @@ namespace IdentityServer4.ResponseHandling
/// <seealso cref="IdentityServer4.ResponseHandling.IIntrospectionResponseGenerator" />
public class IntrospectionResponseGenerator : IIntrospectionResponseGenerator
{
/// <summary>
/// Gets the events.
/// </summary>
/// <value>
/// The events.
/// </value>
protected readonly IEventService Events;

/// <summary>
/// The logger
/// </summary>
protected readonly ILogger Logger;

/// <summary>
/// Initializes a new instance of the <see cref="IntrospectionResponseGenerator"/> class.
/// Initializes a new instance of the <see cref="IntrospectionResponseGenerator" /> class.
/// </summary>
/// <param name="events">The events.</param>
/// <param name="logger">The logger.</param>
public IntrospectionResponseGenerator(ILogger<IntrospectionResponseGenerator> logger)
public IntrospectionResponseGenerator(IEventService events, ILogger<IntrospectionResponseGenerator> logger)
{
Events = events;
Logger = logger;
}

Expand All @@ -51,6 +63,8 @@ public virtual async Task<Dictionary<string, object>> ProcessAsync(Introspection
if (validationResult.IsActive == false)
{
Logger.LogDebug("Creating introspection response for inactive token.");
await Events.RaiseAsync(new TokenIntrospectionSuccessEvent(validationResult));

return response;
}

Expand All @@ -74,6 +88,7 @@ public virtual async Task<Dictionary<string, object>> ProcessAsync(Introspection
scopes = scopes.Where(x => allowedScopes.Contains(x));
response.Add("scope", scopes.ToSpaceSeparatedString());

await Events.RaiseAsync(new TokenIntrospectionSuccessEvent(validationResult));
return response;
}

Expand All @@ -82,11 +97,12 @@ public virtual async Task<Dictionary<string, object>> ProcessAsync(Introspection
/// </summary>
/// <param name="validationResult">The validation result.</param>
/// <returns></returns>
protected virtual Task<bool> AreExpectedScopesPresentAsync(IntrospectionRequestValidationResult validationResult)
protected virtual async Task<bool> AreExpectedScopesPresentAsync(IntrospectionRequestValidationResult validationResult)
{
var apiScopes = validationResult.Api.Scopes.Select(x => x.Name);
var tokenScopesThatMatchApi = validationResult.Claims.Where(
c => c.Type == JwtClaimTypes.Scope && apiScopes.Contains(c.Value));
var tokenScopes = validationResult.Claims.Where(c => c.Type == JwtClaimTypes.Scope);

var tokenScopesThatMatchApi = tokenScopes.Where(c => apiScopes.Contains(c.Value));

var result = false;

Expand All @@ -99,9 +115,10 @@ protected virtual Task<bool> AreExpectedScopesPresentAsync(IntrospectionRequestV
{
// no scopes for this API are found in the token
Logger.LogError("Expected scope {scopes} is missing in token", apiScopes);
await Events.RaiseAsync(new TokenIntrospectionFailureEvent(validationResult.Api.Name, "Expected scopes are missing", validationResult.Token, apiScopes, tokenScopes.Select(s => s.Value)));
}

return Task.FromResult(result);
return result;
}
}
}

0 comments on commit 4611ac9

Please sign in to comment.