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

V4: Make client claims serialization friendly #3887

Merged
merged 8 commits into from
Dec 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Security.Claims;
using AutoMapper;
using IdentityServer4.Models;

namespace IdentityServer4.EntityFramework.Mappers
{
Expand Down Expand Up @@ -38,8 +39,8 @@ public ClientMapperProfile()
.ReverseMap()
.ForMember(dest => dest.Provider, opt => opt.MapFrom(src => src));

CreateMap<Entities.ClientClaim, Claim>(MemberList.None)
.ConstructUsing(src => new Claim(src.Type, src.Value))
CreateMap<Entities.ClientClaim, ClientClaim>(MemberList.None)
.ConstructUsing(src => new ClientClaim(src.Type, src.Value, ClaimValueTypes.String))
.ReverseMap();

CreateMap<Entities.ClientScope, string>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public async Task FindClientByIdAsync_WhenClientExistsWithCollections_ExpectClie
AllowedCorsOrigins = {"https://localhost"},
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
AllowedScopes = {"openid", "profile", "api1"},
Claims = {new Claim("test", "value")},
Claims = {new ClientClaim("test", "value")},
ClientSecrets = {new Secret("secret".Sha256())},
IdentityProviderRestrictions = {"AD"},
PostLogoutRedirectUris = {"https://locahost/signout-callback"},
Expand Down
12 changes: 11 additions & 1 deletion src/IdentityServer4/host/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@
"ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ],
"AllowedGrantTypes": [ "client_credentials" ],
"AllowedScopes": [ "api1", "api2.read_only" ],
"Properties": {"foo": "bar" }
"Properties": { "foo": "bar" },
"Claims": [
{
"type": "c1",
"value": "c1value"
},
{
"type": "c2",
"value": "c2value"
}
]
},
{
"ClientId": "hybrid",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public void SetClient(Client client, ParsedSecret secret = null, string confirma

AccessTokenLifetime = client.AccessTokenLifetime;
AccessTokenType = client.AccessTokenType;
ClientClaims = client.Claims.Select(c => new Claim(c.Type, c.Value, c.ValueType, c.Issuer)).ToList();
ClientClaims = client.Claims.Select(c => new Claim(c.Type, c.Value, c.ValueType)).ToList();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public DefaultClaimsServiceTests()
_client = new Client
{
ClientId = "client",
Claims = { new Claim("some_claim", "some_claim_value") }
Claims = { new ClientClaim("some_claim", "some_claim_value") }
};

_user = new IdentityServerUser("bob")
Expand Down
2 changes: 1 addition & 1 deletion src/Storage/src/Models/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public ICollection<string> AllowedGrantTypes
/// <value>
/// The claims.
/// </value>
public ICollection<Claim> Claims { get; set; } = new HashSet<Claim>(new ClaimComparer());
public ICollection<ClientClaim> Claims { get; set; } = new HashSet<ClientClaim>();

/// <summary>
/// Gets or sets a value indicating whether client claims should be always included in the access tokens - or only for client credentials flow.
Expand Down
89 changes: 89 additions & 0 deletions src/Storage/src/Models/ClientClaim.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// 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 System;
using System.Security.Claims;

namespace IdentityServer4.Models
{
/// <summary>
/// A client claim
/// </summary>
public class ClientClaim
{
/// <summary>
/// The claim type
/// </summary>
public string Type { get; set; }

/// <summary>
/// The claim value
/// </summary>
public string Value { get; set; }

/// <summary>
/// The claim value type
/// </summary>
public string ValueType { get; set; } = ClaimValueTypes.String;

/// <summary>
/// ctor
/// </summary>
public ClientClaim()
{
}

/// <summary>
/// ctor
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
public ClientClaim(string type, string value)
{
Type = type;
Value = value;
}

/// <summary>
/// ctor
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <param name="valueType"></param>
public ClientClaim(string type, string value, string valueType)
{
Type = type;
Value = value;
ValueType = valueType;
}

/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hash = 17;

hash = hash * 23 + Value.GetHashCode();
hash = hash * 23 + Type.GetHashCode();
hash = hash * 23 + ValueType.GetHashCode();
return hash;
}
}

/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is null) return false;
if (obj is ClientClaim c)
{
return (string.Equals(Type, c.Type, StringComparison.Ordinal) &&
string.Equals(Value, c.Value, StringComparison.Ordinal) &&
string.Equals(ValueType, c.ValueType, StringComparison.Ordinal));
}

return false;
}
}
}