Skip to content

Commit

Permalink
Merge branch 'release/1.1'
Browse files Browse the repository at this point in the history
- Added Resource Indicators support (RFC 8707)
- Fixed issuer parameter return from Authorization endpoint ([PR#11](#11))
- Fixed some suggestions from SonarQube
  • Loading branch information
kirill-abblix committed Jul 9, 2024
2 parents c65e702 + 8686f36 commit cc81b66
Show file tree
Hide file tree
Showing 107 changed files with 2,651 additions and 644 deletions.
93 changes: 93 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: [ "master", "develop" ]
pull_request:
branches: [ "master", "develop" ]
schedule:
- cron: '0 0 * * 1' # Weekly schedule at midnight UTC on Mondays

jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read

strategy:
fail-fast: false
matrix:
include:
- language: csharp
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
2 changes: 2 additions & 0 deletions Abblix.DependencyInjection/Abblix.DependencyInjection.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<PackageReleaseNotes>For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases</PackageReleaseNotes>
<PackageIcon>Abblix.png</PackageIcon>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<FileVersion>1.1.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions Abblix.Jwt.UnitTests/Abblix.Jwt.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
4 changes: 2 additions & 2 deletions Abblix.Jwt.UnitTests/JwtEncryptionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public async Task JwtFullCycleTest()
{
ValidateAudience = aud => Task.FromResult(token.Payload.Audiences.SequenceEqual(aud)),
ValidateIssuer = iss => Task.FromResult(iss == token.Payload.Issuer),
ResolveTokenDecryptionKeys = _ => new [] { EncryptingKey }.AsAsync(),
ResolveIssuerSigningKeys = _ => new [] { SigningKey }.AsAsync(),
ResolveTokenDecryptionKeys = _ => new [] { EncryptingKey }.ToAsyncEnumerable(),
ResolveIssuerSigningKeys = _ => new [] { SigningKey }.ToAsyncEnumerable(),
};

var result = Assert.IsType<ValidJsonWebToken>(await validator.ValidateAsync(jwt, parameters));
Expand Down
5 changes: 4 additions & 1 deletion Abblix.Jwt/Abblix.Jwt.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
<PackageReleaseNotes>For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases</PackageReleaseNotes>
<PackageIcon>Abblix.png</PackageIcon>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<FileVersion>1.1.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.2" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
27 changes: 26 additions & 1 deletion Abblix.Jwt/JsonWebKeyFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// info@abblix.com

using System.Security.Cryptography;
using Abblix.Utils;
using Microsoft.IdentityModel.Tokens;

namespace Abblix.Jwt;
Expand Down Expand Up @@ -53,12 +54,14 @@ public static class JsonWebKeyFactory
rsa.KeySize = keySize;
var parameters = rsa.ExportParameters(true);

var parametersExponent = parameters.Exponent;
var key = new JsonWebKey
{
KeyType = "RSA",
KeyId = parameters.ToKeyId(),
Algorithm = algorithm,
Usage = usage,
RsaExponent = parameters.Exponent,
RsaExponent = parametersExponent,
RsaModulus = parameters.Modulus,
PrivateKey = parameters.D,
FirstPrimeFactor = parameters.P,
Expand All @@ -70,4 +73,26 @@ public static class JsonWebKeyFactory

return key;
}

private static string ToKeyId(this RSAParameters parameters)
{
var keyMaterial = (parameters.Modulus, parameters.Exponent) switch
{
({} modulus, {} exponent) => modulus.Concat(exponent),
({} modulus, null) => modulus,
(null, {} exponent) => exponent,
(null, null) => Array.Empty<byte>(),
};

// Compute the SHA-256 hash of the concatenated string
return SHA256.HashData(keyMaterial).ToHexString();
}

private static byte[] Concat(this byte[] modulus, byte[] exponent)
{
var buffer = new byte[modulus.Length + exponent.Length];
Array.Copy(modulus, buffer, modulus.Length);
Array.Copy(exponent, 0, buffer, modulus.Length, exponent.Length);
return buffer;
}
}
8 changes: 4 additions & 4 deletions Abblix.Jwt/JsonWebTokenValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ private static JwtValidationResult Validate(string jwt, ValidationParameters par
var signingKeys = resolveIssuerSigningKeys(securityToken.Issuer);
if (keyId.HasValue())
signingKeys = signingKeys.WhereAsync(key => key.KeyId == keyId);
signingKeys = signingKeys.Where(key => key.KeyId == keyId);
return signingKeys.SelectAsync(key => key.ToSecurityKey()).ToListAsync().Result;
return signingKeys.Select(key => key.ToSecurityKey()).ToListAsync().Result;
};
}

Expand All @@ -109,9 +109,9 @@ private static JwtValidationResult Validate(string jwt, ValidationParameters par
var decryptionKeys = resolveTokenDecryptionKeys(securityToken.Issuer);
if (keyId.HasValue())
decryptionKeys = decryptionKeys.WhereAsync(key => key.KeyId == keyId);
decryptionKeys = decryptionKeys.Where(key => key.KeyId == keyId);
return decryptionKeys.SelectAsync(key => key.ToSecurityKey()).ToListAsync().Result;
return decryptionKeys.Select(key => key.ToSecurityKey()).ToListAsync().Result;
};

var handler = new JwtSecurityTokenHandler();
Expand Down
4 changes: 3 additions & 1 deletion Abblix.Oidc.Server.Mvc/Abblix.Oidc.Server.Mvc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
<PackageReleaseNotes>For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases</PackageReleaseNotes>
<PackageIcon>Abblix.png</PackageIcon>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<FileVersion>1.1.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -35,7 +37,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Microsoft.AspNetCore.Http;

namespace Abblix.Oidc.Server.Mvc.ActionResults;

public static class CookieOptionsExtensions
{
/// <summary>
Expand Down
12 changes: 6 additions & 6 deletions Abblix.Oidc.Server.Mvc/Attributes/AbsoluteUriAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,24 @@ public sealed class AbsoluteUriAttribute : ValidationAttribute
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <param name="value">The value of the object to validate.</param>
/// <param name="context">The context information about the object being validated.</param>
/// <param name="validationContext">The context information about the object being validated.</param>
/// <returns><see cref="ValidationResult.Success"/> if the value is a valid absolute URI, otherwise an error <see cref="ValidationResult"/>.</returns>
protected override ValidationResult? IsValid(object? value, ValidationContext context)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
=> value switch
{
null => ValidationResult.Success, // absence is OK, apply [Required] if needed

string str when string.IsNullOrEmpty(str) => ValidationResult.Success,
Uri uri when string.IsNullOrEmpty(uri.OriginalString) => ValidationResult.Success,

string str when Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out var uri) => IsValid(uri, context),
string str when Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out var uri) => IsValid(uri, validationContext),

Uri { IsAbsoluteUri: true, Scheme: var scheme } when RequireScheme.HasValue() && !string.Equals(RequireScheme, scheme, StringComparison.OrdinalIgnoreCase)
=> new ValidationResult($"{context.GetName()} value must use {RequireScheme} scheme."),
=> new ValidationResult($"{validationContext.GetName()} value must use {RequireScheme} scheme."),

Uri { IsAbsoluteUri: true } => ValidationResult.Success,

Uri => new ValidationResult($"{context.GetName()} value is not absolute."),
_ => new ValidationResult($"{context.GetName()} is not Uri, but {value.GetType().Name}."),
Uri => new ValidationResult($"{validationContext.GetName()} value is not absolute."),
_ => new ValidationResult($"{validationContext.GetName()} is not Uri, but {value.GetType().Name}."),
};
}
10 changes: 5 additions & 5 deletions Abblix.Oidc.Server.Mvc/Attributes/AllowedValuesAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ public AllowedValuesAttribute(params string[] allowedValues)
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <param name="value">The value of the object to validate.</param>
/// <param name="context">The context information about the object being validated.</param>
/// <param name="validationContext">The context information about the object being validated.</param>
/// <returns><see cref="ValidationResult.Success"/> if the value is among the allowed values,
/// otherwise an error <see cref="ValidationResult"/>.
/// </returns>
protected override ValidationResult? IsValid(object? value, ValidationContext context)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
return value switch
{
null => ValidationResult.Success,
string[][] stringValues => IsValid(stringValues.SelectMany(stringValue => stringValue), context),
string[] stringValues => IsValid(stringValues, context),
string[][] stringValues => IsValid(stringValues.SelectMany(stringValue => stringValue)),
string[] stringValues => IsValid(stringValues),
string stringValue => IsValid(stringValue),
_ => throw new InvalidOperationException($"The type {value.GetType()} is not supported by {nameof(AllowedValuesAttribute)}"),
};
}

private ValidationResult? IsValid(IEnumerable<string> values, ValidationContext context)
private ValidationResult? IsValid(IEnumerable<string> values)
{
foreach (var value in values)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ public abstract class ConditionalRequiredAttribute : RequiredAttribute
/// Determines whether the specified value of the object is valid based on a custom condition.
/// </summary>
/// <param name="value">The value of the object to validate.</param>
/// <param name="context">The context information about the object being validated.</param>
/// <param name="validationContext">The context information about the object being validated.</param>
/// <returns>
/// <see cref="ValidationResult.Success"/> if the condition is not met or if the value is valid as per the base <see cref="RequiredAttribute"/>;
/// otherwise, an error <see cref="ValidationResult"/>.
/// </returns>
protected override ValidationResult? IsValid(object? value, ValidationContext context)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (!IsRequired(context.ObjectInstance))
if (!IsRequired(validationContext.ObjectInstance))
return ValidationResult.Success;

return base.IsValid(value, context);
return base.IsValid(value, validationContext);
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions Abblix.Oidc.Server.Mvc/AutoPostFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ public AutoPostFormatter(IParametersProvider parametersProvider, Uri action)
/// This method overrides the base class implementation to write an HTML form with the specified parameters.
/// </summary>
/// <param name="context">The context for the output formatter.</param>
/// <param name="encoding">The encoding to use for the response.</param>
/// <param name="selectedEncoding">The encoding to use for the response.</param>
/// <returns>A task that represents the asynchronous write operation.</returns>
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding encoding)
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
if (context.Object == null)
return;

var settings = new XmlWriterSettings { Async = true, Encoding = encoding };
var settings = new XmlWriterSettings { Async = true, Encoding = selectedEncoding };
await using var writer = XmlWriter.Create(context.HttpContext.Response.Body, settings);

var parameters = _parametersProvider.GetParameters(context.Object);
Expand Down
5 changes: 2 additions & 3 deletions Abblix.Oidc.Server.Mvc/Controllers/DiscoveryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
using Abblix.Oidc.Server.Features.LogoutNotification;
using Abblix.Oidc.Server.Features.UserInfo;
using Abblix.Oidc.Server.Model;
using Abblix.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
Expand Down Expand Up @@ -163,8 +162,8 @@ public async Task<ActionResult<JsonWebKeySet>> KeysAsync(
if (!options.Value.EnabledEndpoints.HasFlag(OidcEndpoints.Keys))
return NotFound();

var keys = await serviceKeysProvider.GetSigningKeys().ToListAsync();
return Json(new JsonWebKeySet(keys.ToArray()));
var keys = await serviceKeysProvider.GetSigningKeys().ToArrayAsync();
return Json(new JsonWebKeySet(keys));
}

private static JsonResult Json(object response) => new(
Expand Down
Loading

0 comments on commit cc81b66

Please sign in to comment.