Skip to content

Commit

Permalink
AddGetUserInfoAsync method
Browse files Browse the repository at this point in the history
  • Loading branch information
Shoogn committed Feb 23, 2024
1 parent 7f5b9cf commit c8678c3
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 8 deletions.
17 changes: 17 additions & 0 deletions Server/src/OAuth20.Server/OAuthResponse/UserInfoResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace OAuth20.Server.OAuthResponse
{
public class UserInfoResponse
{
public bool Succeeded { get; set; }
public string Error { get; set; } = string.Empty;

public string ErrorDescription { get; set; }
public bool HasError => !string.IsNullOrEmpty(Error);


/// <summary>
/// Returned result as json.
/// </summary>
public string Claims { get; set; }
}
}
61 changes: 56 additions & 5 deletions Server/src/OAuth20.Server/Services/IClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,65 @@ Everyone is permitted to copy and distribute verbatim copies
using System;
using Microsoft.AspNetCore.Http;
using OAuth20.Server.Enumeration;
using OAuth20.Server.Models.Context;
using Microsoft.IdentityModel.Tokens;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace OAuth20.Server.Services
{
public interface IClientService
{
CheckClientResult VerifyClientById(string clientId, bool checkWithSecret = false,string clientSecret = null,
CheckClientResult VerifyClientById(string clientId, bool checkWithSecret = false, string clientSecret = null,
string grantType = null);

bool SearchForClientBySecret(string grantType);
AudienceValidator ValidateAudienceHandler(IEnumerable<string> audiences, SecurityToken securityToken,
TokenValidationParameters validationParameters, Client client, string token);

Task<CheckClientResult> GetClientByIdAsync(string clientId);
}

public class ClientService : IClientService
{
private readonly ClientStore _clientStore = new ClientStore();
private readonly IHttpContextAccessor _httpContextAccessor;
public ClientService(IHttpContextAccessor httpContextAccessor)
private readonly BaseDBContext _dbContext;
public ClientService(IHttpContextAccessor httpContextAccessor,
BaseDBContext context)
{
_httpContextAccessor = httpContextAccessor;
_dbContext = context;
}

public Task<CheckClientResult> GetClientByIdAsync(string clientId)
{
var c = _clientStore.Clients.Where(x => x.ClientId == clientId).FirstOrDefault();
var response = new CheckClientResult
{
Client = c,
IsSuccess = true
};
return Task.FromResult(response);
//var client = await _dbContext.OAuthApplications.FirstOrDefaultAsync
// (x=>x.ClientId == clientId);
//if(client == null)
//{

//}
//else
//{
// var c = _clientStore.Clients.Where(x => x.ClientId == clientId).FirstOrDefault();
//}
}

public CheckClientResult VerifyClientById(string clientId, bool checkWithSecret = false, string clientSecret = null,
public CheckClientResult VerifyClientById(string clientId, bool checkWithSecret = false, string clientSecret = null,
string grantType = null)
{
CheckClientResult result = new CheckClientResult() { IsSuccess = false };

if (!string.IsNullOrWhiteSpace(grantType) &&
if (!string.IsNullOrWhiteSpace(grantType) &&
grantType == AuthorizationGrantTypesEnum.ClientCredentials.GetEnumDescription())
{
var data = _httpContextAccessor.HttpContext;
Expand All @@ -65,7 +98,7 @@ public CheckClientResult VerifyClientById(string clientId, bool checkWithSecret
{
var client = _clientStore
.Clients
.Where(x =>
.Where(x =>
x.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();

Expand Down Expand Up @@ -111,5 +144,23 @@ public bool SearchForClientBySecret(string grantType)

return false;
}

public AudienceValidator ValidateAudienceHandler(IEnumerable<string> audiences, SecurityToken securityToken,
TokenValidationParameters validationParameters, Client client, string token)
{
Func<IEnumerable<string>, SecurityToken, TokenValidationParameters, bool> handler = (audiences, securityToken, validationParameters) =>
{
// Check the Token the Back Store.
var tokenInDb = _dbContext.OAuthTokens.FirstOrDefault(x => x.Token == token);
if (tokenInDb == null)
return false;

if (tokenInDb.Revoked)
return false;

return true;
};
return new AudienceValidator(handler);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class TokenIntrospectionService : ITokenIntrospectionService
private readonly ILogger<TokenIntrospectionService> _logger;
private readonly BaseDBContext _dbContext;
private readonly OAuthServerOptions _optionsMonitor;
private readonly ClientStore _clientStore = new ClientStore();
public TokenIntrospectionService(
ITokenIntrospectionValidation tokenIntrospectionValidation,
ILogger<TokenIntrospectionService> logger,
Expand Down
106 changes: 104 additions & 2 deletions Server/src/OAuth20.Server/Services/UserInfoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ Everyone is permitted to copy and distribute verbatim copies
*/

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OAuth20.Server.Configuration;
using OAuth20.Server.OauthRequest;
using OAuth20.Server.OAuthResponse;
using OAuth20.Server.Validations;
using System;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace OAuth20.Server.Services;

Expand All @@ -17,10 +30,99 @@ public interface IUserInfoService
public class UserInfoService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserInfoService(IHttpContextAccessor httpContextAccessor)
private readonly IBearerTokenUsageTypeValidation _bearerTokenUsageTypeValidation;
private readonly OAuthServerOptions _optionsMonitor;
private readonly IClientService _clientService;

public UserInfoService(IHttpContextAccessor httpContextAccessor,
IBearerTokenUsageTypeValidation bearerTokenUsageTypeValidation,
IOptionsMonitor<OAuthServerOptions> optionsMonitor,
IClientService clientService)
{
_httpContextAccessor = httpContextAccessor;
_bearerTokenUsageTypeValidation= bearerTokenUsageTypeValidation;
_optionsMonitor = optionsMonitor.CurrentValue ?? new OAuthServerOptions();
_clientService = clientService;
}


public async Task<UserInfoResponse> GetUserInfoAsync()
{
var bearerTokenUsages = await _bearerTokenUsageTypeValidation.ValidateAsync();
if (bearerTokenUsages.Succeeded == false)
{
return new UserInfoResponse
{
Claims = null,
Succeeded = false,
Error = "no token found",
ErrorDescription = "Make sure to add the token as bearer to Authentication header in the request"

};
}
else
{
// validate to token
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
string publicPrivateKey = File.ReadAllText("PublicPrivateKey.xml");
provider.FromXmlString(publicPrivateKey);
RsaSecurityKey rsaSecurityKey = new RsaSecurityKey(provider);
JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(bearerTokenUsages.Token);

var clientId = jwtSecurityToken.Audiences.FirstOrDefault();
var client = await _clientService.GetClientByIdAsync(clientId);

// check if client is null.
// check if client is not active.

TokenValidationParameters tokenValidationParameters = new TokenValidationParameters();

tokenValidationParameters.IssuerSigningKey = rsaSecurityKey;
tokenValidationParameters.ValidAudiences = jwtSecurityToken.Audiences;
tokenValidationParameters.ValidTypes = new[] { "JWT" };
tokenValidationParameters.ValidateIssuer = true;
tokenValidationParameters.ValidIssuer = _optionsMonitor.IDPUri;
tokenValidationParameters.ValidateAudience = true;
tokenValidationParameters.AudienceValidator = _clientService.ValidateAudienceHandler(
jwtSecurityToken.Audiences, jwtSecurityToken,
tokenValidationParameters, client.Client, bearerTokenUsages.Token);

try
{
var tokenValidationReslt = await jwtSecurityTokenHandler.ValidateTokenAsync(bearerTokenUsages.Token, tokenValidationParameters);

if (tokenValidationReslt.IsValid)
{
int exp = (int)tokenValidationReslt.Claims.FirstOrDefault(x => x.Key == "exp").Value;
string scope = (tokenValidationReslt.Claims.FirstOrDefault(x => x.Key == "scope").Value).ToString();
string aud = (tokenValidationReslt.Claims.FirstOrDefault(x => x.Key == "aud").Value).ToString();


//response.Active = true;
//response.TokenType = "access_token";
//response.Exp = exp;
//response.Iat = (int)jwtSecurityToken.IssuedAt.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
//response.Iss = _optionsMonitor.IDPUri;
//response.Scope = scope;
//response.Aud = aud;
//response.Nbf = (int)jwtSecurityToken.IssuedAt.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
}
}
catch (Exception ex) // maybe SecurityTokenException
{
//_logger.LogCritical("There is an exception that is thrown while validating the token {exception}", ex);
//response.Active = false;
return new UserInfoResponse
{
Claims = null,
Succeeded = false,
Error = "invalid_token",
ErrorDescription = "token is not valid"

};
}

return null;
}
}
}

0 comments on commit c8678c3

Please sign in to comment.