Skip to content

Commit

Permalink
client: Introduces client_secret_expires_at to client metadata (#870)
Browse files Browse the repository at this point in the history
This patch introduces the `client_secret_expires_at` field without any functionality but to comply with the IETF spec.

Closes #778
  • Loading branch information
zepatrik authored and arekkas committed May 25, 2018
1 parent e5aefd8 commit 56aa5d2
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 15 deletions.
6 changes: 6 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ type Client struct {
// 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" gorethink:"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
// measured in UTC until the date/time of expiration.
SecretExpiresAt int `json:"client_secret_expires_at" gorethink:"client_secret_expires_at"`
}

func (c *Client) GetID() string {
Expand Down
7 changes: 7 additions & 0 deletions client/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request, _ httprouter.Pa
return
}

// has to be 0 because it is not supposed to be set
c.SecretExpiresAt = 0

secret := c.Secret
if err := h.Manager.CreateClient(&c); err != nil {
h.H.WriteError(w, r, err)
Expand Down Expand Up @@ -143,6 +146,10 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request, ps httprouter.P
}

c.ID = ps.ByName("id")

// has to be 0 because it is not supposed to be set
c.SecretExpiresAt = 0

if err := h.Manager.UpdateClient(&c); err != nil {
h.H.WriteError(w, r, err)
return
Expand Down
13 changes: 13 additions & 0 deletions client/manager_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ var migrations = &migrate.MemoryMigrationSource{
"DROP TABLE hydra_client",
},
},
{
Id: "2",
Up: []string{
`ALTER TABLE hydra_client ADD client_secret_expires_at INTEGER NOT NULL DEFAULT 0`,
},
Down: []string{
`ALTER TABLE hydra_client DROP COLUMN client_secret_expires_at`,
},
},
},
}

Expand All @@ -82,6 +91,7 @@ type sqlData struct {
LogoURI string `db:"logo_uri"`
Contacts string `db:"contacts"`
Public bool `db:"public"`
SecretExpiresAt int `db:"client_secret_expires_at"`
}

var sqlParams = []string{
Expand All @@ -99,6 +109,7 @@ var sqlParams = []string{
"logo_uri",
"contacts",
"public",
"client_secret_expires_at",
}

func sqlDataFromClient(d *Client) *sqlData {
Expand All @@ -117,6 +128,7 @@ func sqlDataFromClient(d *Client) *sqlData {
LogoURI: d.LogoURI,
Contacts: strings.Join(d.Contacts, "|"),
Public: d.Public,
SecretExpiresAt: d.SecretExpiresAt,
}
}

Expand All @@ -136,6 +148,7 @@ func (d *sqlData) ToClient() *Client {
LogoURI: d.LogoURI,
Contacts: stringsx.Splitx(d.Contacts, "|"),
Public: d.Public,
SecretExpiresAt: d.SecretExpiresAt,
}
}

Expand Down
6 changes: 6 additions & 0 deletions client/manager_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestHelperCreateGetDeleteClient(k string, m Storage) func(t *testing.T) {
Secret: "secret",
RedirectURIs: []string{"http://redirect"},
TermsOfServiceURI: "foo",
SecretExpiresAt: 0,
}

assert.NoError(t, m.CreateClient(c))
Expand All @@ -85,6 +86,7 @@ func TestHelperCreateGetDeleteClient(k string, m Storage) func(t *testing.T) {
Secret: "secret",
RedirectURIs: []string{"http://redirect"},
TermsOfServiceURI: "foo",
SecretExpiresAt: 1,
}))

d, err := m.GetClient(nil, "1234")
Expand All @@ -99,6 +101,10 @@ func TestHelperCreateGetDeleteClient(k string, m Storage) func(t *testing.T) {
assert.Len(t, ds, 2)
assert.NotEqual(t, ds["1234"].ID, ds["2-1234"].ID)

//test if SecretExpiresAt was set properly
assert.Equal(t, ds["1234"].SecretExpiresAt, 0)
assert.Equal(t, ds["2-1234"].SecretExpiresAt, 1)

ds, err = m.GetClients(1, 0)
assert.NoError(t, err)
assert.Len(t, ds, 1)
Expand Down
44 changes: 29 additions & 15 deletions client/sdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,20 @@ import (

func createTestClient(prefix string) hydra.OAuth2Client {
return hydra.OAuth2Client{
Id: "1234",
ClientName: prefix + "name",
ClientSecret: prefix + "secret",
ClientUri: prefix + "uri",
Contacts: []string{prefix + "peter", prefix + "pan"},
GrantTypes: []string{prefix + "client_credentials", prefix + "authorize_code"},
LogoUri: prefix + "logo",
Owner: prefix + "an-owner",
PolicyUri: prefix + "policy-uri",
Scope: prefix + "foo bar baz",
TosUri: prefix + "tos-uri",
ResponseTypes: []string{prefix + "id_token", prefix + "code"},
RedirectUris: []string{prefix + "redirect-url", prefix + "redirect-uri"},
Id: "1234",
ClientName: prefix + "name",
ClientSecret: prefix + "secret",
ClientUri: prefix + "uri",
Contacts: []string{prefix + "peter", prefix + "pan"},
GrantTypes: []string{prefix + "client_credentials", prefix + "authorize_code"},
LogoUri: prefix + "logo",
Owner: prefix + "an-owner",
PolicyUri: prefix + "policy-uri",
Scope: prefix + "foo bar baz",
TosUri: prefix + "tos-uri",
ResponseTypes: []string{prefix + "id_token", prefix + "code"},
RedirectUris: []string{prefix + "redirect-url", prefix + "redirect-uri"},
SecretExpiresAt: 0,
}
}

Expand All @@ -65,32 +66,45 @@ func TestClientSDK(t *testing.T) {

t.Run("case=client is created and updated", func(t *testing.T) {
createClient := createTestClient("")
compareClient := createClient
createClient.SecretExpiresAt = 10

// returned client is correct on Create
result, _, err := c.CreateOAuth2Client(createClient)
require.NoError(t, err)
assert.EqualValues(t, createClient, *result)
assert.EqualValues(t, compareClient, *result)

compareClient := createClient
// secret is not returned on GetOAuth2Client
compareClient.ClientSecret = ""
result, _, err = c.GetOAuth2Client(createClient.Id)
assert.EqualValues(t, compareClient, *result)

// listing clients returns the only added one
results, _, err := c.ListOAuth2Clients(100, 0)
require.NoError(t, err)
assert.Len(t, results, 1)
assert.EqualValues(t, compareClient, results[0])

// SecretExpiresAt gets overwritten with 0 on Update
compareClient.ClientSecret = createClient.ClientSecret
result, _, err = c.UpdateOAuth2Client(createClient.Id, createClient)
require.NoError(t, err)
assert.EqualValues(t, compareClient, *result)

// create another client
updateClient := createTestClient("foo")
result, _, err = c.UpdateOAuth2Client(createClient.Id, updateClient)
require.NoError(t, err)
assert.EqualValues(t, updateClient, *result)

// again, test if secret is not returned on Get
compareClient = updateClient
compareClient.ClientSecret = ""
result, _, err = c.GetOAuth2Client(updateClient.Id)
require.NoError(t, err)
assert.EqualValues(t, compareClient, *result)

// client can not be found after being deleted
_, err = c.DeleteOAuth2Client(updateClient.Id)
require.NoError(t, err)

Expand Down
5 changes: 5 additions & 0 deletions docs/api.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,11 @@
"type": "object",
"title": "Client represents an OAuth 2.0 Client.",
"properties": {
"SecretExpiresAt": {
"description": "SecretExpiresAt is an integer holding the time at which the client\nsecret will expire or 0 if it will not expire. The time is\nrepresented as the number of seconds from 1970-01-01T00:00:00Z as\nmeasured in UTC until the date/time of expiration.",
"type": "integer",
"format": "int64"
},
"client_name": {
"description": "Name is the human-readable string name of the client to be presented to the\nend-user during authorization.",
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions sdk/go/hydra/swagger/docs/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**SecretExpiresAt** | **int64** | 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 measured in UTC until the date/time of expiration. | [optional] [default to null]
**ClientName** | **string** | Name is the human-readable string name of the client to be presented to the end-user during authorization. | [optional] [default to null]
**ClientSecret** | **string** | Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again. | [optional] [default to null]
**ClientUri** | **string** | ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion. | [optional] [default to null]
Expand Down
3 changes: 3 additions & 0 deletions sdk/go/hydra/swagger/o_auth2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ package swagger

type OAuth2Client struct {

// 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 measured in UTC until the date/time of expiration.
SecretExpiresAt int64 `json:"SecretExpiresAt,omitempty"`

// Name is the human-readable string name of the client to be presented to the end-user during authorization.
ClientName string `json:"client_name,omitempty"`

Expand Down
1 change: 1 addition & 0 deletions sdk/js/swagger/docs/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**secretExpiresAt** | **Number** | 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 measured in UTC until the date/time of expiration. | [optional]
**clientName** | **String** | Name is the human-readable string name of the client to be presented to the end-user during authorization. | [optional]
**clientSecret** | **String** | Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again. | [optional]
**clientUri** | **String** | ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion. | [optional]
Expand Down
11 changes: 11 additions & 0 deletions sdk/js/swagger/src/model/OAuth2Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
if (data) {
obj = obj || new exports()

if (data.hasOwnProperty('SecretExpiresAt')) {
obj['SecretExpiresAt'] = ApiClient.convertToType(
data['SecretExpiresAt'],
'Number'
)
}
if (data.hasOwnProperty('client_name')) {
obj['client_name'] = ApiClient.convertToType(
data['client_name'],
Expand Down Expand Up @@ -124,6 +130,11 @@
return obj
}

/**
* 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 measured in UTC until the date/time of expiration.
* @member {Number} SecretExpiresAt
*/
exports.prototype['SecretExpiresAt'] = undefined
/**
* Name is the human-readable string name of the client to be presented to the end-user during authorization.
* @member {String} client_name
Expand Down
1 change: 1 addition & 0 deletions sdk/php/swagger/docs/Model/OAuth2Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**secret_expires_at** | **int** | 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 measured in UTC until the date/time of expiration. | [optional]
**client_name** | **string** | Name is the human-readable string name of the client to be presented to the end-user during authorization. | [optional]
**client_secret** | **string** | Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again. | [optional]
**client_uri** | **string** | ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion. | [optional]
Expand Down
27 changes: 27 additions & 0 deletions sdk/php/swagger/lib/Model/OAuth2Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class OAuth2Client implements ArrayAccess
* @var string[]
*/
protected static $swaggerTypes = [
'secret_expires_at' => 'int',
'client_name' => 'string',
'client_secret' => 'string',
'client_uri' => 'string',
Expand All @@ -75,6 +76,7 @@ class OAuth2Client implements ArrayAccess
* @var string[]
*/
protected static $swaggerFormats = [
'secret_expires_at' => 'int64',
'client_name' => null,
'client_secret' => null,
'client_uri' => null,
Expand Down Expand Up @@ -106,6 +108,7 @@ public static function swaggerFormats()
* @var string[]
*/
protected static $attributeMap = [
'secret_expires_at' => 'SecretExpiresAt',
'client_name' => 'client_name',
'client_secret' => 'client_secret',
'client_uri' => 'client_uri',
Expand All @@ -128,6 +131,7 @@ public static function swaggerFormats()
* @var string[]
*/
protected static $setters = [
'secret_expires_at' => 'setSecretExpiresAt',
'client_name' => 'setClientName',
'client_secret' => 'setClientSecret',
'client_uri' => 'setClientUri',
Expand All @@ -150,6 +154,7 @@ public static function swaggerFormats()
* @var string[]
*/
protected static $getters = [
'secret_expires_at' => 'getSecretExpiresAt',
'client_name' => 'getClientName',
'client_secret' => 'getClientSecret',
'client_uri' => 'getClientUri',
Expand Down Expand Up @@ -197,6 +202,7 @@ public static function getters()
*/
public function __construct(array $data = null)
{
$this->container['secret_expires_at'] = isset($data['secret_expires_at']) ? $data['secret_expires_at'] : null;
$this->container['client_name'] = isset($data['client_name']) ? $data['client_name'] : null;
$this->container['client_secret'] = isset($data['client_secret']) ? $data['client_secret'] : null;
$this->container['client_uri'] = isset($data['client_uri']) ? $data['client_uri'] : null;
Expand Down Expand Up @@ -245,6 +251,27 @@ public function valid()
}


/**
* Gets secret_expires_at
* @return int
*/
public function getSecretExpiresAt()
{
return $this->container['secret_expires_at'];
}

/**
* Sets secret_expires_at
* @param int $secret_expires_at 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 measured in UTC until the date/time of expiration.
* @return $this
*/
public function setSecretExpiresAt($secret_expires_at)
{
$this->container['secret_expires_at'] = $secret_expires_at;

return $this;
}

/**
* Gets client_name
* @return string
Expand Down

0 comments on commit 56aa5d2

Please sign in to comment.