Browse Source

Introduce response type permissions, remove hybrid clients support and bring back none flow support

pull/1143/head
Kévin Chalet 5 years ago
parent
commit
84facf0895
  1. 2
      samples/Mvc.Server/Worker.cs
  2. 14
      src/OpenIddict.Abstractions/OpenIddictConstants.cs
  3. 30
      src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx
  4. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.ar.xlf
  5. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.de.xlf
  6. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.es.xlf
  7. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.fr.xlf
  8. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.gu.xlf
  9. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.hi.xlf
  10. 242
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.it.xlf
  11. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.nl.xlf
  12. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.tr.xlf
  13. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.zh-Hans.xlf
  14. 4
      src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.zh-Hant.xlf
  15. 1
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  16. 173
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  17. 62
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  18. 1
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  19. 16
      src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs
  20. 155
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  21. 33
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  22. 173
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs
  23. 1
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs
  24. 1
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
  25. 60
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

2
samples/Mvc.Server/Worker.cs

@ -58,6 +58,7 @@ namespace Mvc.Server
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
Permissions.ResponseTypes.Code,
Permissions.Scopes.Email,
Permissions.Scopes.Profile,
Permissions.Scopes.Roles,
@ -99,6 +100,7 @@ namespace Mvc.Server
Permissions.GrantTypes.DeviceCode,
Permissions.GrantTypes.Password,
Permissions.GrantTypes.RefreshToken,
Permissions.ResponseTypes.Code,
Permissions.Scopes.Email,
Permissions.Scopes.Profile,
Permissions.Scopes.Roles

14
src/OpenIddict.Abstractions/OpenIddictConstants.cs

@ -144,7 +144,6 @@ namespace OpenIddict.Abstractions
public static class ClientTypes
{
public const string Confidential = "confidential";
public const string Hybrid = "hybrid";
public const string Public = "public";
}
@ -357,9 +356,22 @@ namespace OpenIddict.Abstractions
{
public const string Endpoint = "ept:";
public const string GrantType = "gt:";
public const string ResponseType = "rst:";
public const string Scope = "scp:";
}
public static class ResponseTypes
{
public const string Code = "rst:code";
public const string CodeIdToken = "rst:code id_token";
public const string CodeIdTokenToken = "rst:code id_token token";
public const string CodeToken = "rst:code token";
public const string IdToken = "rst:id_token";
public const string IdTokenToken = "rst:id_token token";
public const string None = "rst:none";
public const string Token = "rst:token";
}
public static class Scopes
{
public const string Address = "scp:address";

30
src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx

@ -1381,6 +1381,14 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<value>The duration cannot be less than 10 minutes.</value>
<comment>{Locked}</comment>
</data>
<data name="ID0281" xml:space="preserve">
<value>The authorization code flow must be enabled when adding a response type containing '{0}'.</value>
<comment>{Locked}</comment>
</data>
<data name="ID0282" xml:space="preserve">
<value>The implicit flow must be enabled when adding a response type containing '{0}'.</value>
<comment>{Locked}</comment>
</data>
<data name="ID2000" xml:space="preserve">
<value>The security token is missing.</value>
</data>
@ -1706,7 +1714,7 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<value>An application with the same client identifier already exists.</value>
</data>
<data name="ID2112" xml:space="preserve">
<value>Only confidential, hybrid or public applications are supported by the default application manager.</value>
<value>Only confidential or public applications are supported by the default application manager.</value>
</data>
<data name="ID2113" xml:space="preserve">
<value>The client secret cannot be null or empty for a confidential application.</value>
@ -2023,11 +2031,11 @@ The principal used to create the token contained the following claims: {Claims}.
<comment>{Locked}</comment>
</data>
<data name="ID6060" xml:space="preserve">
<value>The device request was rejected because the confidential or hybrid application '{ClientId}' didn't specify a client secret.</value>
<value>The device request was rejected because the confidential application '{ClientId}' didn't specify a client secret.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6061" xml:space="preserve">
<value>The device request was rejected because the confidential or hybrid application '{ClientId}' didn't specify valid client credentials.</value>
<value>The device request was rejected because the confidential application '{ClientId}' didn't specify valid client credentials.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6062" xml:space="preserve">
@ -2119,11 +2127,11 @@ The principal used to create the token contained the following claims: {Claims}.
<comment>{Locked}</comment>
</data>
<data name="ID6084" xml:space="preserve">
<value>The token request was rejected because the confidential or hybrid application '{ClientId}' didn't specify a client secret.</value>
<value>The token request was rejected because the confidential application '{ClientId}' didn't specify a client secret.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6085" xml:space="preserve">
<value>The token request was rejected because the confidential or hybrid application '{ClientId}' didn't specify valid client credentials.</value>
<value>The token request was rejected because the confidential application '{ClientId}' didn't specify valid client credentials.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6086" xml:space="preserve">
@ -2187,11 +2195,11 @@ The principal used to create the token contained the following claims: {Claims}.
<comment>{Locked}</comment>
</data>
<data name="ID6101" xml:space="preserve">
<value>The introspection request was rejected because the confidential or hybrid application '{ClientId}' didn't specify a client secret.</value>
<value>The introspection request was rejected because the confidential application '{ClientId}' didn't specify a client secret.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6102" xml:space="preserve">
<value>The introspection request was rejected because the confidential or hybrid application '{ClientId}' didn't specify valid client credentials.</value>
<value>The introspection request was rejected because the confidential application '{ClientId}' didn't specify valid client credentials.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6103" xml:space="preserve">
@ -2231,11 +2239,11 @@ The principal used to create the token contained the following claims: {Claims}.
<comment>{Locked}</comment>
</data>
<data name="ID6114" xml:space="preserve">
<value>The revocation request was rejected because the confidential or hybrid application '{ClientId}' didn't specify a client secret.</value>
<value>The revocation request was rejected because the confidential application '{ClientId}' didn't specify a client secret.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6115" xml:space="preserve">
<value>The revocation request was rejected because the confidential or hybrid application '{ClientId}' didn't specify valid client credentials.</value>
<value>The revocation request was rejected because the confidential application '{ClientId}' didn't specify valid client credentials.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6116" xml:space="preserve">
@ -2491,6 +2499,10 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<value>A signing key of type '{Type}' was ignored because its EC curve couldn't be inferred.</value>
<comment>{Locked}</comment>
</data>
<data name="ID6181" xml:space="preserve">
<value>The authorization request was rejected because the application '{ClientId}' was not allowed to use the '{ResponseType}' response type.</value>
<comment>{Locked}</comment>
</data>
<data name="ID8000" xml:space="preserve">
<value>Removes orphaned tokens and authorizations from the database.</value>
</data>

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.ar.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">يتم دعم التطبيقات السرية أو الهجينة أو العامة فقط من قبل مدير التطبيق الافتراضي.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">يتم دعم التطبيقات السرية أو الهجينة أو العامة فقط من قبل مدير التطبيق الافتراضي.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.de.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">Nur Confidential, Hybrid oder Public Anwendungen werden vom Standardanwendungsmanager unterstützt.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">Nur Confidential, Hybrid oder Public Anwendungen werden vom Standardanwendungsmanager unterstützt.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.es.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">El administrador de aplicaciones predeterminado solo admite aplicaciones confidenciales, híbridas o públicas.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">El administrador de aplicaciones predeterminado solo admite aplicaciones confidenciales, híbridas o públicas.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.fr.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">Seules les applications confidentielles, hybrides ou publiques sont supportées par le gestionnaire d'application par défaut.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="translated">Seules les applications confidentielles ou publiques sont supportées par le gestionnaire d'application par défaut.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.gu.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">મૂળભૂત એપ્લિકેશન મેનેજર દ્વારા ફક્ત ગોપનીય, વર્ણસંકર અથવા સાર્વજનિક એપ્લિકેશનોને ટેકો આપવામાં આવે છે.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">મૂળભૂત એપ્લિકેશન મેનેજર દ્વારા ફક્ત ગોપનીય, વર્ણસંકર અથવા સાર્વજનિક એપ્લિકેશનોને ટેકો આપવામાં આવે છે.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.hi.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">केवल गोपनीय, हाइब्रिड या सार्वजनिक एप्लिकेशन डिफ़ॉल्ट एप्लिकेशन मैनेजर द्वारा समर्थित हैं.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">केवल गोपनीय, हाइब्रिड या सार्वजनिक एप्लिकेशन डिफ़ॉल्ट एप्लिकेशन मैनेजर द्वारा समर्थित हैं.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

242
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.it.xlf

@ -5,597 +5,597 @@
<trans-unit id="ID2000">
<source>The security token is missing.</source>
<target state="translated">Il token di sicurezza è mancante.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2001">
<source>The specified authorization code is invalid.</source>
<target state="translated">Il codice di autorizzazione specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2002">
<source>The specified device code is invalid.</source>
<target state="translated">Il codice del dispositivo specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2003">
<source>The specified refresh token is invalid.</source>
<target state="translated">Il token di aggiornamento specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2004">
<source>The specified token is invalid.</source>
<target state="translated">Il token specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2005">
<source>The specified token is not an authorization code.</source>
<target state="translated">Il token specificato non è un codice di autorizzazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2006">
<source>The specified token is not an device code.</source>
<target state="translated">Il token specificato non è un codice del dispositivo.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2007">
<source>The specified token is not a refresh token.</source>
<target state="translated">Il token specificato non è un token di aggiornamento.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2008">
<source>The specified token is not an access token.</source>
<target state="translated">Il token specificato non è un token di accesso.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2009">
<source>The specified identity token is invalid.</source>
<target state="translated">Il token di identità specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2010">
<source>The specified authorization code has already been redeemed.</source>
<target state="translated">Il codice di autorizzazione specificato è già stato utilizzato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2011">
<source>The specified device code has already been redeemed.</source>
<target state="translated">Il codice di dispositivo specificato è già stato utilizzato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2012">
<source>The specified refresh token has already been redeemed.</source>
<target state="translated">Il token di aggiornamento specificato è già stato utilizzato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2013">
<source>The specified token has already been redeemed.</source>
<target state="translated">Il codice specificato è già stato utilizzato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2014">
<source>The authorization has not been granted yet by the end user.</source>
<target state="translated">L'autorizzazione non è ancora stata concessa dall'utente finale.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2015">
<source>The authorization was denied by the end user.</source>
<target state="translated">L'autorizzazione è stata negata dall'utente finale.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2016">
<source>The specified authorization code is no longer valid.</source>
<target state="translated">Il codice di autorizzazione specificato non è più valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2017">
<source>The specified device code is no longer valid.</source>
<target state="translated">Il codice del dispositivo specificato non è più valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2018">
<source>The specified refresh token is no longer valid.</source>
<target state="translated">Il token di aggiornamento specificato non è più valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2019">
<source>The specified token is no longer valid.</source>
<target state="translated">Il token specificato non è più valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2020">
<source>The authorization associated with the authorization code is no longer valid.</source>
<target state="translated">L'autorizzazione associata con il codice di autorizzazione non è più valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2021">
<source>The authorization associated with the device code is no longer valid.</source>
<target state="translated">L'autorizzazione associata con il codice del dispositivo non è più valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2022">
<source>The authorization associated with the refresh token is no longer valid.</source>
<target state="translated">L'autorizzazione associata con il token di aggiornamento non è più valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2023">
<source>The authorization associated with the token is no longer valid.</source>
<target state="translated">L'autorizzazione associata con il token non è più valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2024">
<source>The token request was rejected by the authentication server.</source>
<target state="translated">La richiesta del token è stata respinta dal server di autenticazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2025">
<source>The user information access demand was rejected by the authentication server.</source>
<target state="translated">La richiesta di accesso alle informazioni dell'utente è stata rifiutata dal server di autenticazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2026">
<source>The specified user code is no longer valid.</source>
<target state="translated">Il codice utente specificato non è più valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2028">
<source>The '{0}' parameter is not supported.</source>
<target state="translated">Il parametro '{0}' non è supportato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2029">
<source>The mandatory '{0}' parameter is missing.</source>
<target state="translated">Manca il parametro obbligatorio '{0}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2030">
<source>The '{0}' parameter must be a valid absolute URL.</source>
<target state="translated">Il parametro '{0}' deve essere un URL assoluto valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2031">
<source>The '{0}' parameter must not include a fragment.</source>
<target state="translated">Il parametro '{0}' non deve includere un frammento di URL.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2032">
<source>The specified '{0}' is not supported.</source>
<target state="translated">Il '{0}' specificato non è supportato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2033">
<source>The specified '{0}'/'{1}' combination is invalid.</source>
<target state="translated">La combinazione '{0}' / '{1}' specificata non è valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2034">
<source>The mandatory '{0}' scope is missing.</source>
<target state="translated">Manca l'ambito obbligatorio '{0}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2035">
<source>The '{0}' scope is not allowed.</source>
<target state="translated">L'ambito '{0}' non è consentito.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2036">
<source>The client identifier cannot be null or empty.</source>
<target state="translated">L'identificatore del client non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2037">
<source>The '{0}' parameter cannot be used without '{1}'.</source>
<target state="translated">Il parametro '{0}' non può essere utilizzato senza '{1}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2038">
<source>The status cannot be null or empty.</source>
<target state="translated">Lo stato non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2039">
<source>Scopes cannot be null or empty.</source>
<target state="translated">Gli ambiti non possono essere nulli o vuoti.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2040">
<source>The '{0}' and '{1}' parameters can only be used with a response type containing '{2}'.</source>
<target state="translated">I parametri '{0}' e '{1}' possono essere utilizzati solo con un tipo di risposta contenente '{2}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2041">
<source>The specified '{0}' is not allowed when using PKCE.</source>
<target state="translated">Il '{0}' specificato non è consentito quando si utilizza PKCE.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2042">
<source>Scopes cannot contain spaces.</source>
<target state="translated">Gli ambiti non possono contenere spazi.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2043">
<source>The specified '{0}' is not valid for this client application.</source>
<target state="translated">Il '{0}' specificato non è valido per questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2044">
<source>The scope name cannot be null or empty.</source>
<target state="translated">Il nome dell'ambito non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2045">
<source>The scope name cannot contain spaces.</source>
<target state="translated">Il nome dell'ambito non può contenere spazi.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2046">
<source>This client application is not allowed to use the authorization endpoint.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare l'endpoint di autorizzazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2047">
<source>The client application is not allowed to use the authorization code flow.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare il flusso del codice di autorizzazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2048">
<source>The client application is not allowed to use the implicit flow.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare il flusso implicito.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2049">
<source>The client application is not allowed to use the hybrid flow.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare il flusso ibrido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2051">
<source>This client application is not allowed to use the specified scope.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare l'ambito specificato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2052">
<source>The specified '{0}' is invalid.</source>
<target state="translated">Il '{0}' specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2053">
<source>The '{0}' parameter is not valid for this client application.</source>
<target state="translated">Il parametro '{0}' non è valido per questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2054">
<source>The '{0}' parameter required for this client application is missing.</source>
<target state="translated">Manca il parametro '{0}' richiesto per questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2055">
<source>The specified client credentials are invalid.</source>
<target state="translated">Le credenziali client specificate non sono valide.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2056">
<source>This client application is not allowed to use the device endpoint.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare l'endpoint del dispositivo.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2057">
<source>The '{0}' and '{1}' parameters are required when using the client credentials grant.</source>
<target state="translated">I parametri '{0}' e '{1}' sono obbligatori quando si utilizza la concessione delle credenziali del client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2058">
<source>The '{0}' parameter is required when using the device code grant.</source>
<target state="translated">Il parametro '{0}' è obbligatorio quando si utilizza la concessione del codice del dispositivo.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2059">
<source>The mandatory '{0}' and/or '{1}' parameters are missing.</source>
<target state="translated">Mancano i parametri obbligatori '{0}' e / o '{1}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2060">
<source>A scope with the same name already exists.</source>
<target state="translated">Esiste già un ambito con lo stesso nome.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2063">
<source>This client application is not allowed to use the token endpoint.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare l'endpoint del token.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2064">
<source>This client application is not allowed to use the specified grant type.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare il tipo di concessione specificato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2065">
<source>The client application is not allowed to use the '{0}' scope.</source>
<target state="translated">L'applicazione client non può utilizzare l'ambito '{0}'.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2066">
<source>The specified authorization code cannot be used without sending a client identifier.</source>
<target state="translated">Il codice di autorizzazione specificato non può essere utilizzato senza inviare un identificativo client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2067">
<source>The specified device code cannot be used without sending a client identifier.</source>
<target state="translated">Il codice dispositivo specificato non può essere utilizzato senza inviare un identificativo client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2068">
<source>The specified refresh token cannot be used without sending a client identifier.</source>
<target state="translated">Il token di aggiornamento specificato non può essere utilizzato senza inviare un identificatore client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2069">
<source>The specified authorization code cannot be used by this client application.</source>
<target state="translated">Il codice di autorizzazione specificato non può essere utilizzato da questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2070">
<source>The specified device code cannot be used by this client application.</source>
<target state="translated">Il codice del dispositivo specificato non può essere utilizzato da questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2071">
<source>The specified refresh token cannot be used by this client application.</source>
<target state="translated">Il token di aggiornamento specificato non può essere utilizzato da questa applicazione client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2072">
<source>The specified '{0}' parameter doesn't match the client redirection address the authorization code was initially sent to.</source>
<target state="translated">Il parametro '{0}' specificato non corrisponde all'indirizzo di reindirizzamento del client a cui è stato inizialmente inviato il codice di autorizzazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2073">
<source>The '{0}' parameter cannot be used when no '{1}' was specified in the authorization request.</source>
<target state="translated">Il parametro '{0}' non può essere utilizzato se non è stato specificato alcun '{1}' nella richiesta di autorizzazione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2074">
<source>The '{0}' parameter is not valid in this context.</source>
<target state="translated">Il parametro '{0}' non è valido in questo contesto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2075">
<source>This client application is not allowed to use the introspection endpoint.</source>
<target state="translated">L'applicazione client non può utilizzare l'endpoint di introspezione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2076">
<source>The specified token cannot be introspected.</source>
<target state="translated">Il token specificato non può essere esaminato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2077">
<source>The client application is not allowed to introspect the specified token.</source>
<target state="translated">L'applicazione client non è autorizzata a esaminare il token specificato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2078">
<source>This client application is not allowed to use the revocation endpoint.</source>
<target state="translated">L'applicazione client non è autorizzata a utilizzare l'endpoint di revoca.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2079">
<source>This token cannot be revoked.</source>
<target state="translated">Questo token non può essere revocato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2080">
<source>The client application is not allowed to revoke the specified token.</source>
<target state="translated">L'applicazione client non è autorizzata a revocare il token specificato.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2081">
<source>The mandatory '{0}' header is missing.</source>
<target state="translated">Manca l'intestazione '{0}' obbligatoria.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2082">
<source>The specified '{0}' header is invalid.</source>
<target state="translated">L'intestazione '{0}' specificata non è valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2083">
<source>This server only accepts HTTPS requests.</source>
<target state="translated">Questo server accetta solo richieste HTTPS.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2084">
<source>The specified HTTP method is not valid.</source>
<target state="translated">Il metodo HTTP specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2085">
<source>A token with the same reference identifier already exists.</source>
<target state="translated">Esiste già un token con lo stesso identificatore di riferimento.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2086">
<source>The token type cannot be null or empty.</source>
<target state="translated">Il tipo di token non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2087">
<source>Multiple client credentials cannot be specified.</source>
<target state="translated">Non è possibile specificare più credenziali client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2088">
<source>The issuer associated to the specified token is not valid.</source>
<target state="translated">L'emittente associato al token specificato non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2089">
<source>The specified token is not of the expected type.</source>
<target state="translated">Il token specificato non è del tipo previsto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2090">
<source>The signing key associated to the specified token was not found.</source>
<target state="translated">La chiave di firma associata al token specificato non è stata trovata.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2091">
<source>The signature associated to the specified token is not valid.</source>
<target state="translated">La firma associata al token specificato non è valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2092">
<source>This resource server is currently unavailable.</source>
<target state="translated">Questo server di risorse non è attualmente disponibile.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2093">
<source>The specified token doesn't contain any audience.</source>
<target state="needs-l10n">Il token specificato non contiene alcun pubblico.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2094">
<source>The specified token cannot be used with this resource server.</source>
<target state="translated">Il token specificato non può essere utilizzato con questo server di risorse.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2095">
<source>The user represented by the token is not allowed to perform the requested action.</source>
<target state="translated">L'utente rappresentato dal token non è autorizzato a eseguire l'azione richiesta.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2096">
<source>No issuer could be found in the server configuration.</source>
<target state="translated">Nessun emittente è stato trovato nella configurazione del server.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2097">
<source>A server configuration containing an invalid issuer was returned.</source>
<target state="translated">È stata restituita una configurazione del server contenente un emittente non valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2098">
<source>The issuer returned in the server configuration is not valid.</source>
<target state="translated">L'emittente restituito nella configurazione del server non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2099">
<source>No JWKS endpoint could be found in the server configuration.</source>
<target state="translated">Nessun endpoint JWKS è stato trovato nella configurazione del server.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2100">
<source>A server configuration containing an invalid JWKS endpoint URL was returned.</source>
<target state="translated">È stata restituita una configurazione server contenente un URL dell'endpoint JWKS non valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2101">
<source>A server configuration containing an invalid introspection endpoint URL was returned.</source>
<target state="translated">È stata restituita una configurazione del server contenente un URL dell'endpoint di introspezione non valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2102">
<source>The JWKS document didn't contain a valid '{0}' node with at least one key.</source>
<target state="translated">Il documento JWKS non conteneva un nodo '{0}' valido con almeno una chiave.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2103">
<source>A JWKS response containing an unsupported key was returned.</source>
<target state="translated">È stata restituita una risposta JWKS contenente una chiave non supportata.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2104">
<source>A JWKS response containing an invalid key was returned.</source>
<target state="translated">È stata restituita una risposta JWKS contenente una chiave non valida.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2105">
<source>The mandatory '{0}' parameter couldn't be found in the introspection response.</source>
<target state="translated">Impossibile trovare il parametro obbligatorio '{0}' nella risposta di introspezione.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2106">
<source>The token was rejected by the remote authentication server.</source>
<target state="translated">Il token è stato rifiutato dal server di autenticazione remoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2107">
<source>The '{0}' claim is malformed or isn't of the expected type.</source>
<target state="translated">La rivendicazione '{0}' non è valida o non è del tipo previsto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2108">
<source>An introspection response containing a malformed issuer was returned.</source>
<target state="translated">È stata restituita una risposta di introspezione contenente un emittente non valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2109">
<source>The issuer returned in the introspection response is not valid.</source>
<target state="translated">L'emittente restituito nella risposta di introspezione non è valido.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2110">
<source>The type of the introspected token doesn't match the expected type.</source>
<target state="translated">Il tipo di token analizzato non corrisponde al tipo previsto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2111">
<source>An application with the same client identifier already exists.</source>
<target state="translated">Esiste già un'applicazione con lo stesso identificatore client.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">Solo le applicazioni riservate, ibride o pubbliche sono supportate dal gestore applicazioni predefinito.</target>
<note/>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">Solo le applicazioni riservate, ibride o pubbliche sono supportate dal gestore applicazioni predefinito.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">
<source>The client secret cannot be null or empty for a confidential application.</source>
<target state="translated">Il segreto client non può essere nullo o vuoto per un'applicazione riservata.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2114">
<source>A client secret cannot be associated with a public application.</source>
<target state="translated">Un segreto client non può essere associato a un'applicazione pubblica.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2115">
<source>Callback URLs cannot contain a fragment.</source>
<target state="translated">Gli URL di richiamata non possono contenere un frammento.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2116">
<source>The authorization type cannot be null or empty.</source>
<target state="translated">Il tipo di autorizzazione non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2117">
<source>The specified authorization type is not supported by the default token manager.</source>
<target state="translated">Il tipo di autorizzazione specificato non è supportato dal gestore di token predefinito.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2118">
<source>The client type cannot be null or empty.</source>
<target state="translated">Il tipo di client non può essere nullo o vuoto.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2119">
<source>Callback URLs cannot be null or empty.</source>
<target state="translated">Gli URL di richiamata non possono essere nulli o vuoti.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID2120">
<source>Callback URLs must be valid absolute URLs.</source>
<target state="translated">Gli URL di richiamata devono essere URL assoluti validi.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID8000">
<source>Removes orphaned tokens and authorizations from the database.</source>
<target state="translated">Rimuove i token e le autorizzazioni orfani dal database.</target>
<note/>
<note />
</trans-unit>
<trans-unit id="ID8001">
<source>Starts the scheduled task at regular intervals.</source>
<target state="translated">Avvia l'attività pianificata a intervalli regolari.</target>
<note/>
<note />
</trans-unit>
</body>
</file>

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.nl.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">Alleen vertrouwelijke, hybride of openbare applicaties worden ondersteund door de standaard applicatiebeheerder.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">Alleen vertrouwelijke, hybride of openbare applicaties worden ondersteund door de standaard applicatiebeheerder.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.tr.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">Varsayılan uygulama yöneticisi tarafından sadece gizli, hibrit ve umumi uygulamalar desteklenmektedir.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">Varsayılan uygulama yöneticisi tarafından sadece gizli, hibrit ve umumi uygulamalar desteklenmektedir.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.zh-Hans.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">默认应用程序管理器仅支持机密、混合或公共应用程序.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">默认应用程序管理器仅支持机密、混合或公共应用程序.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

4
src/OpenIddict.Abstractions/Resources/xlf/OpenIddictResources.zh-Hant.xlf

@ -543,8 +543,8 @@
<note />
</trans-unit>
<trans-unit id="ID2112">
<source>Only confidential, hybrid or public applications are supported by the default application manager.</source>
<target state="translated">預設應用程式管理器僅支援機密、混合或公共應用程式.</target>
<source>Only confidential or public applications are supported by the default application manager.</source>
<target state="needs-review-translation">預設應用程式管理器僅支援機密、混合或公共應用程式.</target>
<note />
</trans-unit>
<trans-unit id="ID2113">

1
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -1166,7 +1166,6 @@ namespace OpenIddict.Core
{
// Ensure the application type is supported by the manager.
if (!string.Equals(type, ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{
yield return new ValidationResult(Localizer[SR.ID2112]);

173
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -302,19 +302,19 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentException(SR.GetResourceString(SR.ID0057), nameof(algorithm));
}
switch (algorithm)
return algorithm switch
{
case SecurityAlgorithms.Aes256KW:
return AddEncryptionCredentials(new EncryptingCredentials(CreateSymmetricSecurityKey(256),
algorithm, SecurityAlgorithms.Aes256CbcHmacSha512));
SecurityAlgorithms.Aes256KW
=> AddEncryptionCredentials(new EncryptingCredentials(CreateSymmetricSecurityKey(256),
algorithm, SecurityAlgorithms.Aes256CbcHmacSha512)),
case SecurityAlgorithms.RsaOAEP:
case SecurityAlgorithms.RsaOaepKeyWrap:
return AddEncryptionCredentials(new EncryptingCredentials(CreateRsaSecurityKey(2048),
algorithm, SecurityAlgorithms.Aes256CbcHmacSha512));
SecurityAlgorithms.RsaOAEP or
SecurityAlgorithms.RsaOaepKeyWrap
=> AddEncryptionCredentials(new EncryptingCredentials(CreateRsaSecurityKey(2048),
algorithm, SecurityAlgorithms.Aes256CbcHmacSha512)),
default: throw new InvalidOperationException(SR.GetResourceString(SR.ID0058));
}
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0058)),
};
static SymmetricSecurityKey CreateSymmetricSecurityKey(int size)
{
@ -741,50 +741,49 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentException(SR.GetResourceString(SR.ID0057), nameof(algorithm));
}
switch (algorithm)
return algorithm switch
{
case SecurityAlgorithms.RsaSha256:
case SecurityAlgorithms.RsaSha384:
case SecurityAlgorithms.RsaSha512:
case SecurityAlgorithms.RsaSha256Signature:
case SecurityAlgorithms.RsaSha384Signature:
case SecurityAlgorithms.RsaSha512Signature:
case SecurityAlgorithms.RsaSsaPssSha256:
case SecurityAlgorithms.RsaSsaPssSha384:
case SecurityAlgorithms.RsaSsaPssSha512:
case SecurityAlgorithms.RsaSsaPssSha256Signature:
case SecurityAlgorithms.RsaSsaPssSha384Signature:
case SecurityAlgorithms.RsaSsaPssSha512Signature:
return AddSigningCredentials(new SigningCredentials(CreateRsaSecurityKey(2048), algorithm));
SecurityAlgorithms.RsaSha256 or
SecurityAlgorithms.RsaSha384 or
SecurityAlgorithms.RsaSha512 or
SecurityAlgorithms.RsaSha256Signature or
SecurityAlgorithms.RsaSha384Signature or
SecurityAlgorithms.RsaSha512Signature or
SecurityAlgorithms.RsaSsaPssSha256 or
SecurityAlgorithms.RsaSsaPssSha384 or
SecurityAlgorithms.RsaSsaPssSha512 or
SecurityAlgorithms.RsaSsaPssSha256Signature or
SecurityAlgorithms.RsaSsaPssSha384Signature or
SecurityAlgorithms.RsaSsaPssSha512Signature
=> AddSigningCredentials(new SigningCredentials(CreateRsaSecurityKey(2048), algorithm)),
#if SUPPORTS_ECDSA
case SecurityAlgorithms.EcdsaSha256:
case SecurityAlgorithms.EcdsaSha256Signature:
return AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP256)), algorithm));
case SecurityAlgorithms.EcdsaSha384:
case SecurityAlgorithms.EcdsaSha384Signature:
return AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP384)), algorithm));
case SecurityAlgorithms.EcdsaSha512:
case SecurityAlgorithms.EcdsaSha512Signature:
return AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP521)), algorithm));
SecurityAlgorithms.EcdsaSha256 or
SecurityAlgorithms.EcdsaSha256Signature
=> AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP256)), algorithm)),
SecurityAlgorithms.EcdsaSha384 or
SecurityAlgorithms.EcdsaSha384Signature
=> AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP384)), algorithm)),
SecurityAlgorithms.EcdsaSha512 or
SecurityAlgorithms.EcdsaSha512Signature
=> AddSigningCredentials(new SigningCredentials(new ECDsaSecurityKey(
ECDsa.Create(ECCurve.NamedCurves.nistP521)), algorithm)),
#else
case SecurityAlgorithms.EcdsaSha256:
case SecurityAlgorithms.EcdsaSha384:
case SecurityAlgorithms.EcdsaSha512:
case SecurityAlgorithms.EcdsaSha256Signature:
case SecurityAlgorithms.EcdsaSha384Signature:
case SecurityAlgorithms.EcdsaSha512Signature:
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0069));
SecurityAlgorithms.EcdsaSha256 or
SecurityAlgorithms.EcdsaSha384 or
SecurityAlgorithms.EcdsaSha512 or
SecurityAlgorithms.EcdsaSha256Signature or
SecurityAlgorithms.EcdsaSha384Signature or
SecurityAlgorithms.EcdsaSha512Signature
=> throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0069)),
#endif
default: throw new InvalidOperationException(SR.GetResourceString(SR.ID0058));
}
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0058)),
};
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope",
Justification = "The generated RSA key is attached to the server options.")]
@ -1017,7 +1016,18 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowAuthorizationCodeFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.AuthorizationCode));
=> Configure(options =>
{
options.CodeChallengeMethods.Add(CodeChallengeMethods.Sha256);
options.GrantTypes.Add(GrantTypes.AuthorizationCode);
options.ResponseModes.Add(ResponseModes.FormPost);
options.ResponseModes.Add(ResponseModes.Fragment);
options.ResponseModes.Add(ResponseModes.Query);
options.ResponseTypes.Add(ResponseTypes.Code);
});
/// <summary>
/// Enables client credentials flow support. For more information about this
@ -1050,6 +1060,28 @@ namespace Microsoft.Extensions.DependencyInjection
public OpenIddictServerBuilder AllowDeviceCodeFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.DeviceCode));
/// <summary>
/// Enables hybrid flow support. For more information
/// about this specific OpenID Connect flow, visit
/// http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowHybridFlow()
=> Configure(options =>
{
options.CodeChallengeMethods.Add(CodeChallengeMethods.Sha256);
options.GrantTypes.Add(GrantTypes.AuthorizationCode);
options.GrantTypes.Add(GrantTypes.Implicit);
options.ResponseModes.Add(ResponseModes.FormPost);
options.ResponseModes.Add(ResponseModes.Fragment);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.IdToken);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.Token);
});
/// <summary>
/// Enables implicit flow support. For more information
/// about this specific OAuth 2.0/OpenID Connect flow, visit
@ -1058,7 +1090,25 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowImplicitFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.Implicit));
=> Configure(options =>
{
options.GrantTypes.Add(GrantTypes.Implicit);
options.ResponseModes.Add(ResponseModes.FormPost);
options.ResponseModes.Add(ResponseModes.Fragment);
options.ResponseTypes.Add(ResponseTypes.IdToken);
options.ResponseTypes.Add(ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Token);
});
/// <summary>
/// Enables none flow support. For more information about this specific OAuth 2.0 flow,
/// visit https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#none.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowNoneFlow()
=> Configure(options => options.ResponseTypes.Add(ResponseTypes.None));
/// <summary>
/// Enables password flow support. For more information about this specific
@ -1074,7 +1124,12 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowRefreshTokenFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.RefreshToken));
=> Configure(options =>
{
options.GrantTypes.Add(GrantTypes.RefreshToken);
options.Scopes.Add(Scopes.OfflineAccess);
});
/// <summary>
/// Sets the relative or absolute URLs associated to the authorization endpoint.
@ -1615,24 +1670,28 @@ namespace Microsoft.Extensions.DependencyInjection
=> Configure(options => options.EnableDegradedMode = true);
/// <summary>
/// Disables endpoint permissions enforcement. Calling this method is NOT recommended,
/// unless all the clients are first-party applications you own, control and fully trust.
/// Disables endpoint permissions enforcement. Calling this method is NOT recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder IgnoreEndpointPermissions()
=> Configure(options => options.IgnoreEndpointPermissions = true);
/// <summary>
/// Disables grant type permissions enforcement. Calling this method is NOT recommended,
/// unless all the clients are first-party applications you own, control and fully trust.
/// Disables grant type permissions enforcement. Calling this method is NOT recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder IgnoreGrantTypePermissions()
=> Configure(options => options.IgnoreGrantTypePermissions = true);
/// <summary>
/// Disables scope permissions enforcement. Calling this method is NOT recommended,
/// unless all the clients are first-party applications you own, control and fully trust.
/// Disables response type permissions enforcement. Calling this method is NOT recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder IgnoreResponseTypePermissions()
=> Configure(options => options.IgnoreResponseTypePermissions = true);
/// <summary>
/// Disables scope permissions enforcement. Calling this method is NOT recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder IgnoreScopePermissions()

62
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Extensions.Options;
@ -38,7 +39,8 @@ namespace OpenIddict.Server
{
// Explicitly disable all the features that are implicitly excluded when the degraded mode is active.
options.DisableAuthorizationStorage = options.DisableTokenStorage = true;
options.IgnoreEndpointPermissions = options.IgnoreGrantTypePermissions = options.IgnoreScopePermissions = true;
options.IgnoreEndpointPermissions = options.IgnoreGrantTypePermissions = true;
options.IgnoreResponseTypePermissions = options.IgnoreScopePermissions = true;
options.UseReferenceAccessTokens = options.UseReferenceRefreshTokens = false;
// When the degraded mode is enabled (and the token storage disabled), OpenIddict is not able to dynamically
@ -90,6 +92,26 @@ namespace OpenIddict.Server
throw new InvalidOperationException(SR.GetResourceString(SR.ID0080));
}
// Ensure the grant types/response types configuration is consistent.
foreach (var type in options.ResponseTypes)
{
var types = new HashSet<string>(type.Split(Separators.Space, StringSplitOptions.RemoveEmptyEntries), StringComparer.Ordinal);
if (types.Contains(ResponseTypes.Code) && !options.GrantTypes.Contains(GrantTypes.AuthorizationCode))
{
throw new InvalidOperationException(SR.FormatID0281(ResponseTypes.Code));
}
if (types.Contains(ResponseTypes.IdToken) && !options.GrantTypes.Contains(GrantTypes.Implicit))
{
throw new InvalidOperationException(SR.FormatID0282(ResponseTypes.IdToken));
}
if (types.Contains(ResponseTypes.Token) && !options.GrantTypes.Contains(GrantTypes.Implicit))
{
throw new InvalidOperationException(SR.FormatID0282(ResponseTypes.Token));
}
}
if (options.DisableTokenStorage)
{
if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens)
@ -218,44 +240,6 @@ namespace OpenIddict.Server
options.EncryptionCredentials.Sort((left, right) => Compare(left.Key, right.Key));
options.SigningCredentials.Sort((left, right) => Compare(left.Key, right.Key));
// Automatically add the offline_access scope if the refresh token grant has been enabled.
if (options.GrantTypes.Contains(GrantTypes.RefreshToken))
{
options.Scopes.Add(Scopes.OfflineAccess);
}
if (options.GrantTypes.Contains(GrantTypes.AuthorizationCode))
{
options.CodeChallengeMethods.Add(CodeChallengeMethods.Sha256);
options.ResponseTypes.Add(ResponseTypes.Code);
}
if (options.GrantTypes.Contains(GrantTypes.Implicit))
{
options.ResponseTypes.Add(ResponseTypes.IdToken);
options.ResponseTypes.Add(ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Token);
}
if (options.GrantTypes.Contains(GrantTypes.AuthorizationCode) && options.GrantTypes.Contains(GrantTypes.Implicit))
{
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.IdToken);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.Token);
}
if (options.ResponseTypes.Count != 0)
{
options.ResponseModes.Add(ResponseModes.FormPost);
options.ResponseModes.Add(ResponseModes.Fragment);
if (options.ResponseTypes.Contains(ResponseTypes.Code))
{
options.ResponseModes.Add(ResponseModes.Query);
}
}
foreach (var key in options.EncryptionCredentials
.Select(credentials => credentials.Key)
.Concat(options.SigningCredentials.Select(credentials => credentials.Key)))

1
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -67,6 +67,7 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddSingleton<RequireReferenceAccessTokensEnabled>();
builder.Services.TryAddSingleton<RequireReferenceRefreshTokensEnabled>();
builder.Services.TryAddSingleton<RequireRefreshTokenGenerated>();
builder.Services.TryAddSingleton<RequireResponseTypePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireRevocationRequest>();
builder.Services.TryAddSingleton<RequireRollingTokensDisabled>();
builder.Services.TryAddSingleton<RequireRollingRefreshTokensEnabled>();

16
src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs

@ -318,6 +318,22 @@ namespace OpenIddict.Server
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if response type permissions were disabled.
/// </summary>
public class RequireResponseTypePermissionsEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!context.Options.IgnoreResponseTypePermissions);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a revocation request.
/// </summary>

155
src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs

@ -54,6 +54,7 @@ namespace OpenIddict.Server
ValidateScopes.Descriptor,
ValidateEndpointPermissions.Descriptor,
ValidateGrantTypePermissions.Descriptor,
ValidateResponseTypePermissions.Descriptor,
ValidateScopePermissions.Descriptor,
ValidateProofKeyForCodeExchangeRequirement.Descriptor,
@ -563,6 +564,43 @@ namespace OpenIddict.Server
return default;
}
// Reject code flow requests if the server is not configured to allow the authorization code grant type.
if (context.Request.IsAuthorizationCodeFlow() && !context.Options.GrantTypes.Contains(GrantTypes.AuthorizationCode))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6036), context.Request.ResponseType);
context.Reject(
error: Errors.UnsupportedResponseType,
description: context.Localizer[SR.ID2032, Parameters.ResponseType]);
return default;
}
// Reject implicit flow requests if the server is not configured to allow the implicit grant type.
if (context.Request.IsImplicitFlow() && !context.Options.GrantTypes.Contains(GrantTypes.Implicit))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6036), context.Request.ResponseType);
context.Reject(
error: Errors.UnsupportedResponseType,
description: context.Localizer[SR.ID2032, Parameters.ResponseType]);
return default;
}
// Reject hybrid flow requests if the server is not configured to allow the authorization code or implicit grant types.
if (context.Request.IsHybridFlow() && (!context.Options.GrantTypes.Contains(GrantTypes.AuthorizationCode) ||
!context.Options.GrantTypes.Contains(GrantTypes.Implicit)))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6036), context.Request.ResponseType);
context.Reject(
error: Errors.UnsupportedResponseType,
description: context.Localizer[SR.ID2032, Parameters.ResponseType]);
return default;
}
// Reject requests that specify an unsupported response_type.
var types = new HashSet<string>(context.Request.GetResponseTypes(), StringComparer.Ordinal);
if (!context.Options.ResponseTypes.Any(type =>
@ -945,9 +983,10 @@ namespace OpenIddict.Server
}
/// <summary>
/// Contains the logic responsible of rejecting authorization requests
/// that use a response_type incompatible with the client application.
/// Note: this handler is not used when the degraded mode is enabled.
/// Contains the logic responsible of rejecting authorization requests that use a
/// response_type containing token if the application is a confidential client.
/// Note: this handler is not used when the degraded mode is enabled
/// or when response type permissions enforcement is not disabled.
/// </summary>
public class ValidateClientType : IOpenIddictServerHandler<ValidateAuthorizationRequestContext>
{
@ -986,11 +1025,17 @@ namespace OpenIddict.Server
}
// To prevent downgrade attacks, ensure that authorization requests returning an access token directly
// from the authorization endpoint are rejected if the client_id corresponds to a confidential application.
// Note: when using the authorization code grant, the ValidateClientSecret handler is responsible of rejecting
// the token request if the client_id corresponds to an unauthenticated confidential client.
if (context.Request.HasResponseType(ResponseTypes.Token) &&
await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential))
// from the authorization endpoint are rejected if the client_id corresponds to a confidential application
// and if response type permissions enforcement was explicitly disabled in the server options.
// Users who want to enable this advanced scenario are encouraged to re-enable permissions validation.
//
// Alternatively, this handler can be removed from the handlers list using the events model APIs.
if (!context.Options.IgnoreResponseTypePermissions || !context.Request.HasResponseType(ResponseTypes.Token))
{
return;
}
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6045), context.ClientId);
@ -1246,7 +1291,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
}
// Reject the request if the application is not allowed to use the authorization code flow.
// Reject the request if the application is not allowed to use the authorization code grant.
if (context.Request.IsAuthorizationCodeFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode))
{
@ -1259,7 +1304,7 @@ namespace OpenIddict.Server
return;
}
// Reject the request if the application is not allowed to use the implicit flow.
// Reject the request if the application is not allowed to use the implicit grant.
if (context.Request.IsImplicitFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit))
{
@ -1272,7 +1317,7 @@ namespace OpenIddict.Server
return;
}
// Reject the request if the application is not allowed to use the authorization code/implicit flows.
// Reject the request if the application is not allowed to use the authorization code/implicit grants.
if (context.Request.IsHybridFlow() &&
(!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode) ||
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit)))
@ -1286,8 +1331,8 @@ namespace OpenIddict.Server
return;
}
// Reject the request if the offline_access scope was request and if
// the application is not allowed to use the refresh token grant type.
// Reject the request if the offline_access scope was request and
// if the application is not allowed to use the refresh token grant.
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
{
@ -1302,6 +1347,88 @@ namespace OpenIddict.Server
}
}
/// <summary>
/// Contains the logic responsible of rejecting authorization requests made by unauthorized applications.
/// Note: this handler is not used when the degraded mode is enabled or when grant type permissions are disabled.
/// </summary>
public class ValidateResponseTypePermissions : IOpenIddictServerHandler<ValidateAuthorizationRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateResponseTypePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
public ValidateResponseTypePermissions(IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager;
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>()
.AddFilter<RequireResponseTypePermissionsEnabled>()
.AddFilter<RequireDegradedModeDisabled>()
.UseScopedHandler<ValidateResponseTypePermissions>()
.SetOrder(ValidateGrantTypePermissions.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateAuthorizationRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application is null)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
}
// Reject requests that specify a response_type for which no permission was granted.
if (!await HasPermissionAsync(context.Request.GetResponseTypes()))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6081), context.ClientId, context.Request.ResponseType);
context.Reject(
error: Errors.UnauthorizedClient,
description: context.Localizer[SR.ID2043, Parameters.ResponseType]);
return;
}
async ValueTask<bool> HasPermissionAsync(IEnumerable<string> types)
{
// Note: response type permissions are always prefixed with "rst:".
const string prefix = Permissions.Prefixes.ResponseType;
foreach (var permission in await _applicationManager.GetPermissionsAsync(application))
{
// Ignore permissions that are not response type permissions.
if (!permission.StartsWith(prefix, StringComparison.Ordinal))
{
continue;
}
// Note: response types can be specified in any order. To ensure permissions are correctly
// checked even if the order differs from the one specified in the request, a HashSet is used.
var values = permission.Substring(prefix.Length, permission.Length - prefix.Length)
.Split(Separators.Space, StringSplitOptions.RemoveEmptyEntries);
if (values.Length != 0 && new HashSet<string>(values, StringComparer.Ordinal).SetEquals(types))
{
return true;
}
}
return false;
}
}
}
/// <summary>
/// Contains the logic responsible of rejecting authorization requests made by unauthorized applications.
/// Note: this handler is not used when the degraded mode is enabled or when scope permissions are disabled.
@ -1323,7 +1450,7 @@ namespace OpenIddict.Server
.AddFilter<RequireScopePermissionsEnabled>()
.AddFilter<RequireDegradedModeDisabled>()
.UseScopedHandler<ValidateScopePermissions>()
.SetOrder(ValidateGrantTypePermissions.Descriptor.Order + 1_000)
.SetOrder(ValidateResponseTypePermissions.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();

33
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -276,9 +276,9 @@ namespace OpenIddict.Server
/// <summary>
/// Gets or sets a boolean indicating whether sliding expiration is disabled
/// for refresh tokens. When this option is set to <c>true</c>, refresh tokens
/// are issued with a fixed expiration date: when they expire, a complete
/// authorization flow must be started to retrieve a new refresh token.
/// for refresh tokens. When this option is set to <see langword="true"/>,
/// refresh tokens are issued with a fixed expiration date: when they expire,
/// a complete authorization flow must be started to retrieve a new refresh token.
/// </summary>
public bool DisableSlidingRefreshTokenExpiration { get; set; }
@ -308,38 +308,37 @@ namespace OpenIddict.Server
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect response types enabled for this application.
/// Response types are automatically inferred from the supported standard grant types,
/// but additional values can be added for advanced scenarios (e.g custom type support).
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public HashSet<string> ResponseTypes { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets the OAuth 2.0/OpenID Connect response modes enabled for this application.
/// Response modes are automatically inferred from the supported standard grant types,
/// but additional values can be added for advanced scenarios (e.g custom mode support).
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public HashSet<string> ResponseModes { get; } = new HashSet<string>(StringComparer.Ordinal);
/// <summary>
/// Gets or sets a boolean indicating whether endpoint permissions should be ignored.
/// Setting this property to <c>true</c> is NOT recommended, unless all
/// the clients are first-party applications you own, control and fully trust.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreEndpointPermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether grant type permissions should be ignored.
/// Setting this property to <c>true</c> is NOT recommended, unless all
/// the clients are first-party applications you own, control and fully trust.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreGrantTypePermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether response type permissions should be ignored.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreResponseTypePermissions { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether scope permissions should be ignored.
/// Setting this property to <c>true</c> is NOT recommended, unless all
/// the clients are first-party applications you own, control and fully trust.
/// Setting this property to <see langword="true"/> is NOT recommended.
/// </summary>
public bool IgnoreScopePermissions { get; set; }
@ -353,8 +352,8 @@ namespace OpenIddict.Server
/// <summary>
/// Gets or sets a boolean indicating whether reference access tokens should be used.
/// When set to <c>true</c>, the token payload is stored in the database and a
/// crypto-secure random identifier is returned to the client application.
/// When set to <see langword="true"/>, the token payload is stored in the database
/// and a crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
@ -364,8 +363,8 @@ namespace OpenIddict.Server
/// <summary>
/// Gets or sets a boolean indicating whether reference refresh tokens should be used.
/// When set to <c>true</c>, the token payload is stored in the database and a
/// crypto-secure random identifier is returned to the client application.
/// When set to <see langword="true"/>, the token payload is stored in the database
/// and a crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,

173
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs

@ -489,7 +489,7 @@ namespace OpenIddict.Server.IntegrationTests
}
[Fact]
public async Task ValidateAuthorizationRequest_NoneFlowIsRejected()
public async Task ValidateAuthorizationRequest_UnknownResponseTypeParameterIsRejected()
{
// Arrange
await using var server = await CreateServerAsync(options => options.EnableDegradedMode());
@ -500,7 +500,7 @@ namespace OpenIddict.Server.IntegrationTests
{
ClientId = "Fabrikam",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = ResponseTypes.None
ResponseType = "unknown_response_type"
});
// Assert
@ -508,19 +508,36 @@ namespace OpenIddict.Server.IntegrationTests
Assert.Equal(SR.FormatID2032(Parameters.ResponseType), response.ErrorDescription);
}
[Fact]
public async Task ValidateAuthorizationRequest_UnknownResponseTypeParameterIsRejected()
[Theory]
[InlineData(GrantTypes.AuthorizationCode, "code")]
[InlineData(GrantTypes.AuthorizationCode, "code id_token")]
[InlineData(GrantTypes.AuthorizationCode, "code id_token token")]
[InlineData(GrantTypes.AuthorizationCode, "code token")]
[InlineData(GrantTypes.Implicit, "code id_token")]
[InlineData(GrantTypes.Implicit, "code id_token token")]
[InlineData(GrantTypes.Implicit, "code token")]
[InlineData(GrantTypes.Implicit, "id_token")]
[InlineData(GrantTypes.Implicit, "id_token token")]
[InlineData(GrantTypes.Implicit, "token")]
public async Task ValidateAuthorizationRequest_RequestIsRejectedWhenGrantTypeIsDisabled(string flow, string type)
{
// Arrange
await using var server = await CreateServerAsync(options => options.EnableDegradedMode());
await using var server = await CreateServerAsync(options =>
{
options.Configure(options => options.GrantTypes.Remove(flow));
options.Configure(options => options.ResponseTypes.Clear());
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest
{
ClientId = "Fabrikam",
Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = "unknown_response_type"
ResponseType = type,
Scope = Scopes.OpenId
});
// Assert
@ -529,22 +546,20 @@ namespace OpenIddict.Server.IntegrationTests
}
[Theory]
[InlineData(GrantTypes.AuthorizationCode, "code")]
[InlineData(GrantTypes.AuthorizationCode, "code id_token")]
[InlineData(GrantTypes.AuthorizationCode, "code id_token token")]
[InlineData(GrantTypes.AuthorizationCode, "code token")]
[InlineData(GrantTypes.Implicit, "code id_token")]
[InlineData(GrantTypes.Implicit, "code id_token token")]
[InlineData(GrantTypes.Implicit, "code token")]
[InlineData(GrantTypes.Implicit, "id_token")]
[InlineData(GrantTypes.Implicit, "id_token token")]
[InlineData(GrantTypes.Implicit, "token")]
public async Task ValidateAuthorizationRequest_RequestIsRejectedWhenCorrespondingFlowIsDisabled(string flow, string type)
[InlineData("code")]
[InlineData("code id_token")]
[InlineData("code id_token token")]
[InlineData("code token")]
[InlineData("id_token")]
[InlineData("id_token token")]
[InlineData("none")]
[InlineData("token")]
public async Task ValidateAuthorizationRequest_RequestIsRejectedWhenResponseTypeIsDisabled(string type)
{
// Arrange
await using var server = await CreateServerAsync(options =>
{
options.Configure(options => options.GrantTypes.Remove(flow));
options.Configure(options => options.ResponseTypes.Remove(type));
});
await using var client = await server.CreateClientAsync();
@ -1014,7 +1029,7 @@ namespace OpenIddict.Server.IntegrationTests
[InlineData("code token")]
[InlineData("id_token token")]
[InlineData("token")]
public async Task ValidateAuthorizationRequest_AnAccessTokenCannotBeReturnedWhenClientIsConfidential(string type)
public async Task ValidateAuthorizationRequest_AnAccessTokenIsNotReturnedWhenClientIsConfidential(string type)
{
// Arrange
var application = new OpenIddictApplication();
@ -1026,6 +1041,9 @@ namespace OpenIddict.Server.IntegrationTests
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Confidential, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<string>());
});
await using var server = await CreateServerAsync(options =>
@ -1175,6 +1193,123 @@ namespace OpenIddict.Server.IntegrationTests
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application, permissions[0], It.IsAny<CancellationToken>()), Times.Once());
}
[Theory]
[InlineData("code")]
[InlineData("code id_token")]
[InlineData("code id_token token")]
[InlineData("code token")]
[InlineData("id_token")]
[InlineData("id_token token")]
[InlineData("none")]
[InlineData("token")]
public async Task ValidateAuthorizationRequest_RequestIsRejectedWhenResponseTypePermissionIsNotGranted(string type)
{
// Arrange
var application = new OpenIddictApplication();
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<string>());
});
await using var server = await CreateServerAsync(options =>
{
options.Services.AddSingleton(manager);
options.Configure(options => options.IgnoreResponseTypePermissions = false);
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest
{
ClientId = "Fabrikam",
Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = type,
Scope = Scopes.OpenId
});
// Assert
Assert.Equal(Errors.UnauthorizedClient, response.Error);
Assert.Equal(SR.FormatID2043(Parameters.ResponseType), response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()), Times.Once());
}
[Theory]
[InlineData("code id_token token")]
[InlineData("code token")]
[InlineData("id_token token")]
[InlineData("token")]
public async Task ValidateAuthorizationRequest_RequestIsValidatedWhenExplicitPermissionIsGranted(string type)
{
// Arrange
var application = new OpenIddictApplication();
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create("rst:" + type));
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
});
await using var server = await CreateServerAsync(options =>
{
options.Services.AddSingleton(manager);
options.DisableAuthorizationStorage();
options.DisableTokenStorage();
options.DisableSlidingRefreshTokenExpiration();
options.Configure(options => options.IgnoreResponseTypePermissions = false);
options.AddEventHandler<HandleAuthorizationRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
}));
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest
{
ClientId = "Fabrikam",
Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = type,
Scope = Scopes.OpenId
});
// Assert
Assert.Null(response.Error);
Assert.Null(response.ErrorDescription);
Assert.Null(response.ErrorUri);
Assert.NotNull(response.AccessToken);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async Task ValidateAuthorizationRequest_RequestWithOfflineAccessScopeIsRejectedWhenRefreshTokenPermissionIsNotGranted()
{

1
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Discovery.cs

@ -412,6 +412,7 @@ namespace OpenIddict.Server.IntegrationTests
{
options.Configure(options => options.GrantTypes.Clear());
options.Configure(options => options.GrantTypes.Add(GrantTypes.Implicit));
options.Configure(options => options.ResponseTypes.Clear());
options.SetTokenEndpointUris(Array.Empty<Uri>());
});

1
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs

@ -1068,6 +1068,7 @@ namespace OpenIddict.Server.IntegrationTests
options.EnableDegradedMode();
options.Configure(options => options.GrantTypes.Remove(flow));
options.Configure(options => options.ResponseTypes.Clear());
});
await using var client = await server.CreateClientAsync();

60
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

@ -1639,6 +1639,63 @@ namespace OpenIddict.Server.IntegrationTests
Assert.NotNull(response.RefreshToken);
}
[Fact]
public async Task ProcessSignIn_NoTokenIsReturnedForNoneFlowRequests()
{
// Arrange
await using var server = await CreateServerAsync(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<HandleAuthorizationRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
}));
options.AddEventHandler<ProcessSignInContext>(builder =>
{
builder.UseInlineHandler(context =>
{
Assert.False(context.GenerateAccessToken);
Assert.False(context.GenerateAuthorizationCode);
Assert.False(context.GenerateDeviceCode);
Assert.False(context.GenerateIdentityToken);
Assert.False(context.GenerateRefreshToken);
Assert.False(context.GenerateUserCode);
Assert.False(context.IncludeAccessToken);
Assert.False(context.IncludeAuthorizationCode);
Assert.False(context.IncludeDeviceCode);
Assert.False(context.IncludeIdentityToken);
Assert.False(context.IncludeRefreshToken);
Assert.False(context.IncludeUserCode);
return default;
});
builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500);
});
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest
{
ClientId = "Fabrikam",
Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = ResponseTypes.None,
Scope = Scopes.OpenId
});
// Assert
Assert.Equal(0, response.Count);
}
[Theory]
[InlineData("code")]
[InlineData("code id_token")]
@ -4186,7 +4243,9 @@ namespace OpenIddict.Server.IntegrationTests
options.AllowAuthorizationCodeFlow()
.AllowClientCredentialsFlow()
.AllowHybridFlow()
.AllowImplicitFlow()
.AllowNoneFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
@ -4196,6 +4255,7 @@ namespace OpenIddict.Server.IntegrationTests
// Disable permission enforcement by default.
options.IgnoreEndpointPermissions()
.IgnoreGrantTypePermissions()
.IgnoreResponseTypePermissions()
.IgnoreScopePermissions();
options.AddSigningCertificate(

Loading…
Cancel
Save