Skip to content

Commit

Permalink
client: Deprecate public flag
Browse files Browse the repository at this point in the history
The `public` flag has been deprecated in favor of setting `token_endpoint_auth_method=none`.

Closes #938

Signed-off-by: arekkas <aeneas@ory.am>
  • Loading branch information
arekkas committed Jul 22, 2018
1 parent 2bf24b9 commit 5b60af6
Show file tree
Hide file tree
Showing 17 changed files with 68 additions and 86 deletions.
31 changes: 30 additions & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ before finalizing the upgrade process.
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [1.0.0-beta.8](#100-beta8)
- [Schema Changes](#schema-changes)
- [OAuth 2.0 Client flag `public` has been removed](#oauth-20-client-flag-public-has-been-removed)
- [1.0.0-beta.7](#100-beta7)
- [Regenerated OpenID Connect ID Token cryptographic keys](#regenerated-openid-connect-id-token-cryptographic-keys)
- [1.0.0-beta.5](#100-beta5)
- [OAuth 2.0 Client Response Type changes](#oauth-20-client-response-type-changes)
- [Schema Changes](#schema-changes)
- [Schema Changes](#schema-changes-1)
- [HTTP Error Payload](#http-error-payload)
- [OAuth 2.0 Clients must specify correct `token_endpoint_auth_method`](#oauth-20-clients-must-specify-correct-token_endpoint_auth_method)
- [OAuth 2.0 Client field `id` is now `client_id`](#oauth-20-client-field-id-is-now-client_id)
Expand Down Expand Up @@ -91,6 +94,32 @@ before finalizing the upgrade process.

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## 1.0.0-beta.8

### Schema Changes

This patch introduces some minor database schema changes. Before you apply it, you must run `hydra migrate sql` against
your database.

### OAuth 2.0 Client flag `public` has been removed

Previously, OAuth 2.0 Clients had a flag called `public`. If set to true, the OAuth 2.0 Client was able to exchange
authorize codes for access tokens without a password. This is useful in scenarios where the device can not keep
a secret (browser app, mobile app).

Since OpenID Connect Dynamic Discovery was added, this flag collided with the `token_endpoint_auth_method`. If
`token_endpoint_auth_method` is set to `none`, then that is equal to setting `public` to `true`. To remove this
ambiguity the `public` flag was removed.

If you wish to create a client that runs on an untrusted device (browser app, mobile app), simply set `"token_endpoint_auth_method": "none"`
in the JSON request.

If you are using the ORY Hydra CLI, you can use `--token-endpoint-auth-method none` to achieve what `--public` did
previously.

The SQL migrations will automatically migrate clients that have `public` set to `true` by setting `token_endpoint_auth_method`
to `none`.

## 1.0.0-beta.7

### Regenerated OpenID Connect ID Token cryptographic keys
Expand Down
11 changes: 2 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/ory/fosite"

// Naming the dependency jose is important for go-swagger to work, see https://github.com/go-swagger/go-swagger/issues/1587
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2"
)

// Client represents an OAuth 2.0 Client.
Expand Down Expand Up @@ -95,10 +95,6 @@ type Client struct {
// for this client, typically email addresses.
Contacts []string `json:"contacts"`

// Public is a boolean that identifies this client as public, meaning that it
// does not have a secret. It will disable the client_credentials grant type for this client if set.
Public bool `json:"public"`

// SecretExpiresAt is an integer holding the time at which the client
// secret will expire or 0 if it will not expire. The time is
// represented as the number of seconds from 1970-01-01T00:00:00Z as
Expand Down Expand Up @@ -193,7 +189,7 @@ func (c *Client) GetOwner() string {
}

func (c *Client) IsPublic() bool {
return c.Public
return c.TokenEndpointAuthMethod == "none"
}

func (c *Client) GetJSONWebKeysURI() string {
Expand All @@ -217,9 +213,6 @@ func (c *Client) GetRequestObjectSigningAlgorithm() string {

func (c *Client) GetTokenEndpointAuthMethod() string {
if c.TokenEndpointAuthMethod == "" {
if c.Public {
return "none"
}
return "client_secret_basic"
}
return c.TokenEndpointAuthMethod
Expand Down
5 changes: 3 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ func TestClient(t *testing.T) {
ID: "foo",
RedirectURIs: []string{"foo"},
Scope: "foo bar",
TokenEndpointAuthMethod: "none",
}

assert.EqualValues(t, c.RedirectURIs, c.GetRedirectURIs())
assert.EqualValues(t, []byte(c.Secret), c.GetHashedSecret())
assert.EqualValues(t, fosite.Arguments{"authorization_code"}, c.GetGrantTypes())
assert.EqualValues(t, fosite.Arguments{"code"}, c.GetResponseTypes())
assert.EqualValues(t, (c.Owner), c.GetOwner())
assert.EqualValues(t, (c.Public), c.IsPublic())
assert.EqualValues(t, c.Owner, c.GetOwner())
assert.True(t, c.IsPublic())
assert.Len(t, c.GetScopes(), 2)
assert.EqualValues(t, c.RedirectURIs, c.GetRedirectURIs())
}
2 changes: 1 addition & 1 deletion client/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request, _ httprouter.Pa
}

c.Secret = ""
if !c.Public {
if !c.IsPublic() {
c.Secret = secret
}
h.H.WriteCreated(w, r, ClientsHandlerPath+"/"+c.GetID(), &c)
Expand Down
15 changes: 14 additions & 1 deletion client/manager_0_sql_migrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ var createClientMigrations = []*migrate.Migration{
`DELETE FROM hydra_client WHERE id='4-data'`,
},
},
{
Id: "5-data",
Up: []string{
`INSERT INTO hydra_client (id, client_name, client_secret, redirect_uris, grant_types, response_types, scope, owner, policy_uri, tos_uri, client_uri, logo_uri, contacts, client_secret_expires_at, sector_identifier_uri, jwks, jwks_uri, token_endpoint_auth_method, request_uris, request_object_signing_alg, userinfo_signed_response_alg) VALUES ('5-data', 'some-client', 'abcdef', 'http://localhost|http://google', 'authorize_code|implicit', 'token|id_token', 'foo|bar', 'aeneas', 'http://policy', 'http://tos', 'http://client', 'http://logo', 'aeneas|foo', 0, 'http://sector', '{"keys": []}', 'http://jwks', 'none', 'http://uri1|http://uri2', 'rs256', 'rs526')`,
},
Down: []string{
`DELETE FROM hydra_client WHERE id='5-data'`,
},
},
}

var migrations = map[string]*migrate.MemoryMigrationSource{
Expand All @@ -85,6 +94,8 @@ var migrations = map[string]*migrate.MemoryMigrationSource{
createClientMigrations[2],
client.Migrations["mysql"].Migrations[3],
createClientMigrations[3],
client.Migrations["mysql"].Migrations[4],
createClientMigrations[4],
},
},
"postgres": {
Expand All @@ -98,6 +109,8 @@ var migrations = map[string]*migrate.MemoryMigrationSource{
createClientMigrations[2],
client.Migrations["postgres"].Migrations[3],
createClientMigrations[3],
client.Migrations["postgres"].Migrations[4],
createClientMigrations[4],
},
},
}
Expand Down Expand Up @@ -136,7 +149,7 @@ func TestMigrations(t *testing.T) {
})
}

for _, key := range []string{"1-data", "2-data", "3-data", "4-data"} {
for _, key := range []string{"1-data", "2-data", "3-data", "4-data", "5-data"} {
t.Run("client="+key, func(t *testing.T) {
s := &client.SQLManager{DB: db, Hasher: &fosite.BCrypt{WorkFactor: 4}}
c, err := s.GetConcreteClient(key)
Expand Down
17 changes: 13 additions & 4 deletions client/manager_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ var sharedMigrations = []*migrate.Migration{
`ALTER TABLE hydra_client DROP COLUMN userinfo_signed_response_alg`,
},
},
{
Id: "5",
Up: []string{
`UPDATE hydra_client SET token_endpoint_auth_method='none' WHERE public=TRUE`,
`ALTER TABLE hydra_client DROP COLUMN public`,
},
Down: []string{
`ALTER TABLE hydra_client ADD public BOOLEAN NOT NULL DEFAULT FALSE`,
`UPDATE hydra_client SET public=TRUE WHERE token_endpoint_auth_method='none'`,
},
},
}

var Migrations = map[string]*migrate.MemoryMigrationSource{
Expand All @@ -111,6 +122,7 @@ var Migrations = map[string]*migrate.MemoryMigrationSource{
`ALTER TABLE hydra_client MODIFY request_uris TEXT`,
},
},
sharedMigrations[3],
}},
"postgres": {Migrations: []*migrate.Migration{
sharedMigrations[0],
Expand All @@ -132,6 +144,7 @@ var Migrations = map[string]*migrate.MemoryMigrationSource{
`ALTER TABLE hydra_client ALTER COLUMN request_uris DROP NOT NULL`,
},
},
sharedMigrations[3],
}},
}

Expand All @@ -154,7 +167,6 @@ type sqlData struct {
ClientURI string `db:"client_uri"`
LogoURI string `db:"logo_uri"`
Contacts string `db:"contacts"`
Public bool `db:"public"`
SecretExpiresAt int `db:"client_secret_expires_at"`
SectorIdentifierURI string `db:"sector_identifier_uri"`
JSONWebKeysURI string `db:"jwks_uri"`
Expand All @@ -179,7 +191,6 @@ var sqlParams = []string{
"client_uri",
"logo_uri",
"contacts",
"public",
"client_secret_expires_at",
"sector_identifier_uri",
"jwks",
Expand Down Expand Up @@ -215,7 +226,6 @@ func sqlDataFromClient(d *Client) (*sqlData, error) {
ClientURI: d.ClientURI,
LogoURI: d.LogoURI,
Contacts: strings.Join(d.Contacts, "|"),
Public: d.Public,
SecretExpiresAt: d.SecretExpiresAt,
SectorIdentifierURI: d.SectorIdentifierURI,
JSONWebKeysURI: d.JSONWebKeysURI,
Expand Down Expand Up @@ -243,7 +253,6 @@ func (d *sqlData) ToClient() (*Client, error) {
ClientURI: d.ClientURI,
LogoURI: d.LogoURI,
Contacts: stringsx.Splitx(d.Contacts, "|"),
Public: d.Public,
SecretExpiresAt: d.SecretExpiresAt,
SectorIdentifierURI: d.SectorIdentifierURI,
JSONWebKeysURI: d.JSONWebKeysURI,
Expand Down
1 change: 0 additions & 1 deletion client/manager_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ func TestHelperCreateGetDeleteClient(k string, m Storage) func(t *testing.T) {
ClientURI: "http://client",
LogoURI: "http://logo",
Contacts: []string{"aeneas1", "aeneas2"},
Public: true,
SecretExpiresAt: 0,
SectorIdentifierURI: "https://sector",
JSONWebKeys: &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{{KeyID: "foo", Key: []byte("asdf"), Certificates: []*x509.Certificate{}}}},
Expand Down
2 changes: 1 addition & 1 deletion client/sdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func TestClientSDK(t *testing.T) {

t.Run("case=public client is transmitted without secret", func(t *testing.T) {
result, response, err := c.CreateOAuth2Client(hydra.OAuth2Client{
Public: true,
TokenEndpointAuthMethod: "none",
})
require.NoError(t, err)
require.EqualValues(t, http.StatusCreated, response.StatusCode, "%s", response.Payload)
Expand Down
12 changes: 2 additions & 10 deletions client/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,9 @@ func (v *Validator) Validate(c *Client) error {
}

if c.TokenEndpointAuthMethod == "" {
if c.Public {
c.TokenEndpointAuthMethod = "none"
} else {
c.TokenEndpointAuthMethod = "client_secret_basic"
}
c.TokenEndpointAuthMethod = "client_secret_basic"
} else {
if c.Public && c.TokenEndpointAuthMethod != "none" {
return errors.WithStack(fosite.ErrInvalidRequest.WithHint("If field public is true, then token_endpoint_auth_method must be \"none\"."))
} else if !c.Public && c.TokenEndpointAuthMethod == "none" {
return errors.WithStack(fosite.ErrInvalidRequest.WithHint("If field public is false, then token_endpoint_auth_method can not be \"none\"."))
} else if len(c.JSONWebKeysURI) == 0 && c.JSONWebKeys == nil && c.TokenEndpointAuthMethod == "private_key_jwt" {
if len(c.JSONWebKeysURI) == 0 && c.JSONWebKeys == nil && c.TokenEndpointAuthMethod == "private_key_jwt" {
return errors.WithStack(fosite.ErrInvalidRequest.WithHint("When token_endpoint_auth_method is \"private_key_jwt\", either jwks or jwks_uri must be set."))
}
}
Expand Down
12 changes: 2 additions & 10 deletions client/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,11 @@ func TestValidate(t *testing.T) {
expectErr: true,
},
{
in: &Client{ClientID: "foo", Public: true, TokenEndpointAuthMethod: "client_secret_basic"},
in: &Client{ClientID: "foo", TokenEndpointAuthMethod: "private_key_jwt"},
expectErr: true,
},
{
in: &Client{ClientID: "foo", Public: false, TokenEndpointAuthMethod: "none"},
expectErr: true,
},
{
in: &Client{ClientID: "foo", Public: false, TokenEndpointAuthMethod: "private_key_jwt"},
expectErr: true,
},
{
in: &Client{ClientID: "foo", Public: false, JSONWebKeys: &jose.JSONWebKeySet{}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"},
in: &Client{ClientID: "foo", JSONWebKeys: &jose.JSONWebKeySet{}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"},
expectErr: true,
},
} {
Expand Down
5 changes: 0 additions & 5 deletions docs/api.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2354,11 +2354,6 @@
"type": "string",
"x-go-name": "PolicyURI"
},
"public": {
"description": "Public is a boolean that identifies this client as public, meaning that it\ndoes not have a secret. It will disable the client_credentials grant type for this client if set.",
"type": "boolean",
"x-go-name": "Public"
},
"redirect_uris": {
"description": "RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback .",
"type": "array",
Expand Down
1 change: 0 additions & 1 deletion sdk/go/hydra/swagger/docs/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Name | Type | Description | Notes
**LogoUri** | **string** | LogoURI is an URL string that references a logo for the client. | [optional] [default to null]
**Owner** | **string** | Owner is a string identifying the owner of the OAuth 2.0 Client. | [optional] [default to null]
**PolicyUri** | **string** | PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. | [optional] [default to null]
**Public** | **bool** | Public is a boolean that identifies this client as public, meaning that it does not have a secret. It will disable the client_credentials grant type for this client if set. | [optional] [default to null]
**RedirectUris** | **[]string** | RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback . | [optional] [default to null]
**RequestObjectSigningAlg** | **string** | JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm. | [optional] [default to null]
**RequestUris** | **[]string** | Array of request_uri values that are pre-registered by the RP for use at the OP. Servers MAY cache the contents of the files referenced by these URIs and not retrieve them at the time they are used in a request. OPs can require that request_uri values used be pre-registered with the require_request_uri_registration discovery parameter. | [optional] [default to null]
Expand Down
3 changes: 0 additions & 3 deletions sdk/go/hydra/swagger/o_auth2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ type OAuth2Client struct {
// PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data.
PolicyUri string `json:"policy_uri,omitempty"`

// Public is a boolean that identifies this client as public, meaning that it does not have a secret. It will disable the client_credentials grant type for this client if set.
Public bool `json:"public,omitempty"`

// RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback .
RedirectUris []string `json:"redirect_uris,omitempty"`

Expand Down
1 change: 0 additions & 1 deletion sdk/js/swagger/docs/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Name | Type | Description | Notes
**logoUri** | **String** | LogoURI is an URL string that references a logo for the client. | [optional]
**owner** | **String** | Owner is a string identifying the owner of the OAuth 2.0 Client. | [optional]
**policyUri** | **String** | PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. | [optional]
**_public** | **Boolean** | Public is a boolean that identifies this client as public, meaning that it does not have a secret. It will disable the client_credentials grant type for this client if set. | [optional]
**redirectUris** | **[String]** | RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback . | [optional]
**requestObjectSigningAlg** | **String** | JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm. | [optional]
**requestUris** | **[String]** | Array of request_uri values that are pre-registered by the RP for use at the OP. Servers MAY cache the contents of the files referenced by these URIs and not retrieve them at the time they are used in a request. OPs can require that request_uri values used be pre-registered with the require_request_uri_registration discovery parameter. | [optional]
Expand Down
8 changes: 0 additions & 8 deletions sdk/js/swagger/src/model/OAuth2Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@
'String'
)
}
if (data.hasOwnProperty('public')) {
obj['public'] = ApiClient.convertToType(data['public'], 'Boolean')
}
if (data.hasOwnProperty('redirect_uris')) {
obj['redirect_uris'] = ApiClient.convertToType(data['redirect_uris'], [
'String'
Expand Down Expand Up @@ -236,11 +233,6 @@
* @member {String} policy_uri
*/
exports.prototype['policy_uri'] = undefined
/**
* Public is a boolean that identifies this client as public, meaning that it does not have a secret. It will disable the client_credentials grant type for this client if set.
* @member {Boolean} public
*/
exports.prototype['public'] = undefined
/**
* RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback .
* @member {Array.<String>} redirect_uris
Expand Down
1 change: 0 additions & 1 deletion sdk/php/swagger/docs/Model/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Name | Type | Description | Notes
**logo_uri** | **string** | LogoURI is an URL string that references a logo for the client. | [optional]
**owner** | **string** | Owner is a string identifying the owner of the OAuth 2.0 Client. | [optional]
**policy_uri** | **string** | PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. | [optional]
**public** | **bool** | Public is a boolean that identifies this client as public, meaning that it does not have a secret. It will disable the client_credentials grant type for this client if set. | [optional]
**redirect_uris** | **string[]** | RedirectURIs is an array of allowed redirect urls for the client, for example http://mydomain/oauth/callback . | [optional]
**request_object_signing_alg** | **string** | JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm. | [optional]
**request_uris** | **string[]** | Array of request_uri values that are pre-registered by the RP for use at the OP. Servers MAY cache the contents of the files referenced by these URIs and not retrieve them at the time they are used in a request. OPs can require that request_uri values used be pre-registered with the require_request_uri_registration discovery parameter. | [optional]
Expand Down
Loading

0 comments on commit 5b60af6

Please sign in to comment.