/
ClientBuilder.cs
233 lines (206 loc) · 8.14 KB
/
ClientBuilder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using Duende.IdentityServer;
using Duende.IdentityServer.Models;
namespace Microsoft.AspNetCore.ApiAuthorization.IdentityServer
{
/// <summary>
/// A builder for Clients.
/// </summary>
public class ClientBuilder
{
private const string NativeAppClientRedirectUri = "urn:ietf:wg:oauth:2.0:oob";
readonly Client _client;
private bool _built;
/// <summary>
/// Creates a new builder for a single page application that coexists with an authorization server.
/// </summary>
/// <param name="clientId">The client id for the single page application.</param>
/// <returns>A <see cref="ClientBuilder"/>.</returns>
public static ClientBuilder IdentityServerSPA(string clientId)
{
var client = CreateClient(clientId);
return new ClientBuilder(client)
.WithApplicationProfile(ApplicationProfiles.IdentityServerSPA)
.WithAllowedGrants(GrantTypes.Code)
.WithoutClientSecrets()
.WithPkce()
.WithAllowedOrigins(Array.Empty<string>())
.AllowAccessTokensViaBrowser();
}
/// <summary>
/// Creates a new builder for an externally registered single page application.
/// </summary>
/// <param name="clientId">The client id for the single page application.</param>
/// <returns>A <see cref="ClientBuilder"/>.</returns>
public static ClientBuilder SPA(string clientId)
{
var client = CreateClient(clientId);
return new ClientBuilder(client)
.WithApplicationProfile(ApplicationProfiles.SPA)
.WithAllowedGrants(GrantTypes.Code)
.WithoutClientSecrets()
.WithPkce()
.AllowAccessTokensViaBrowser();
}
/// <summary>
/// Creates a new builder for an externally registered native application.
/// </summary>
/// <param name="clientId">The client id for the native application.</param>
/// <returns>A <see cref="ClientBuilder"/>.</returns>
public static ClientBuilder NativeApp(string clientId)
{
var client = CreateClient(clientId);
return new ClientBuilder(client)
.WithApplicationProfile(ApplicationProfiles.NativeApp)
.WithAllowedGrants(GrantTypes.Code)
.WithRedirectUri(NativeAppClientRedirectUri)
.WithLogoutRedirectUri(NativeAppClientRedirectUri)
.WithPkce()
.WithoutClientSecrets()
.WithScopes(IdentityServerConstants.StandardScopes.OfflineAccess);
}
/// <summary>
/// Initializes a new instance of <see cref="ClientBuilder"/>.
/// </summary>
public ClientBuilder() : this(new Client())
{
}
/// <summary>
/// Initializes a new intance of <see cref="ClientBuilder"/>.
/// </summary>
/// <param name="client">A preconfigured client.</param>
public ClientBuilder(Client client)
{
_client = client;
}
/// <summary>
/// Updates the client id (and name) of the client.
/// </summary>
/// <param name="clientId">The new client id.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithClientId(string clientId)
{
_client.ClientId = clientId;
_client.ClientName = clientId;
return this;
}
/// <summary>
/// Sets the application profile for the client.
/// </summary>
/// <param name="profile">The the profile for the application from <see cref="ApplicationProfiles"/>.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithApplicationProfile(string profile)
{
_client.Properties.Add(ApplicationProfilesPropertyNames.Profile, profile);
return this;
}
/// <summary>
/// Adds the <paramref name="scopes"/> to the list of allowed scopes for the client.
/// </summary>
/// <param name="scopes">The list of scopes.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithScopes(params string[] scopes)
{
foreach (var scope in scopes)
{
_client.AllowedScopes.Add(scope);
}
return this;
}
/// <summary>
/// Adds the <paramref name="redirectUri"/> to the list of valid redirect uris for the client.
/// </summary>
/// <param name="redirectUri">The redirect uri to add.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithRedirectUri(string redirectUri)
{
_client.RedirectUris.Add(redirectUri);
return this;
}
/// <summary>
/// Adds the <paramref name="logoutUri"/> to the list of valid logout redirect uris for the client.
/// </summary>
/// <param name="logoutUri">The logout uri to add.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithLogoutRedirectUri(string logoutUri)
{
_client.PostLogoutRedirectUris.Add(logoutUri);
return this;
}
/// <summary>
/// Adds the <paramref name="clientSecret"/> to the list of client secrets for the client and configures the client to
/// require using the secret when getting tokens from the token endpoint.
/// </summary>
/// <param name="clientSecret">The client secret to add.</param>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
internal ClientBuilder WithClientSecret(string clientSecret)
{
_client.ClientSecrets.Add(new Secret(clientSecret));
_client.RequireClientSecret = true;
return this;
}
/// <summary>
/// Removes any configured client secret from the client and configures it to not require a client secret for getting tokens
/// from the token endpoint.
/// </summary>
/// <returns>The <see cref="ClientBuilder"/>.</returns>
public ClientBuilder WithoutClientSecrets()
{
_client.RequireClientSecret = false;
_client.ClientSecrets.Clear();
return this;
}
/// <summary>
/// Builds the client.
/// </summary>
/// <returns>The built <see cref="Client"/>.</returns>
public Client Build()
{
if (_built)
{
throw new InvalidOperationException("Client already built.");
}
_built = true;
return _client;
}
internal ClientBuilder WithPkce()
{
_client.RequirePkce = true;
_client.AllowPlainTextPkce = false;
return this;
}
internal ClientBuilder FromConfiguration()
{
_client.Properties[ApplicationProfilesPropertyNames.Source] = ApplicationProfilesPropertyValues.Configuration;
return this;
}
internal ClientBuilder WithAllowedGrants(ICollection<string> grants)
{
_client.AllowedGrantTypes = grants;
return this;
}
internal ClientBuilder WithAllowedOrigins(params string[] origins)
{
_client.AllowedCorsOrigins = origins;
return this;
}
internal ClientBuilder AllowAccessTokensViaBrowser()
{
_client.AllowAccessTokensViaBrowser = true;
return this;
}
private static Client CreateClient(string name)
{
var client = new Client
{
ClientId = name,
ClientName = name,
RequireConsent = false
};
return client;
}
}
}