Skip to content

Commit

Permalink
Add support for token_endpoint_auth_method (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
amihalj authored and aeneasr committed Nov 26, 2019
1 parent 84b05ca commit cb8601c
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 20 deletions.
20 changes: 15 additions & 5 deletions api/v1alpha1/oauth2client_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ type OAuth2ClientSpec struct {
// HydraAdmin is the optional configuration to use for managing
// this client
HydraAdmin HydraAdmin `json:"hydraAdmin,omitempty"`

// +kubebuilder:validation:Enum=;client_secret_basic;client_secret_post;private_key_jwt;none
//
// Indication which authenticaiton method shoud be used for the token endpoint
TokenEndpointAuthMethod TokenEndpointAuthMethod `json:"tokenEndpointAuthMethod,omitempty"`
}

// +kubebuilder:validation:Enum=client_credentials;authorization_code;implicit;refresh_token
Expand All @@ -114,6 +119,10 @@ type ResponseType string
// RedirectURI represents a redirect URI for the client
type RedirectURI string

// +kubebuilder:validation:Enum=;client_secret_basic;client_secret_post;private_key_jwt;none
// TokenEndpointAuthMethod represents an authenticaiton method for token endpoint
type TokenEndpointAuthMethod string

// OAuth2ClientStatus defines the observed state of OAuth2Client
type OAuth2ClientStatus struct {
// ObservedGeneration represents the most recent generation observed by the daemon set controller.
Expand Down Expand Up @@ -157,11 +166,12 @@ func init() {
// ToOAuth2ClientJSON converts an OAuth2Client into a OAuth2ClientJSON object that represents an OAuth2 client digestible by ORY Hydra
func (c *OAuth2Client) ToOAuth2ClientJSON() *hydra.OAuth2ClientJSON {
return &hydra.OAuth2ClientJSON{
GrantTypes: grantToStringSlice(c.Spec.GrantTypes),
ResponseTypes: responseToStringSlice(c.Spec.ResponseTypes),
RedirectURIs: redirectToStringSlice(c.Spec.RedirectURIs),
Scope: c.Spec.Scope,
Owner: fmt.Sprintf("%s/%s", c.Name, c.Namespace),
GrantTypes: grantToStringSlice(c.Spec.GrantTypes),
ResponseTypes: responseToStringSlice(c.Spec.ResponseTypes),
RedirectURIs: redirectToStringSlice(c.Spec.RedirectURIs),
Scope: c.Spec.Scope,
Owner: fmt.Sprintf("%s/%s", c.Name, c.Namespace),
TokenEndpointAuthMethod: string(c.Spec.TokenEndpointAuthMethod),
}
}

Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/hydra.ory.sh_oauth2clients.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,14 @@ spec:
maxItems: 3
minItems: 1
type: array
tokenEndpointAuthMethod:
description: Indication which authenticaiton method shoud be used for the token endpoint.
type: string
enum:
- client_secret_basic
- client_secret_post
- private_key_jwt
- none
scope:
description: Scope is a string containing a space-separated list of
scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749])
Expand Down
4 changes: 1 addition & 3 deletions config/samples/hydra_v1alpha1_oauth2client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ spec:
- id_token
- code
- token
redirectUris:
- https://client/account
- http://localhost:8080
scope: "read write"
secretName: my-secret-123
# these are optional
Expand All @@ -29,4 +26,5 @@ spec:
port: 4445
endpoint: /clients
forwardedProto: https
tokenEndpointAuthMethod: client_secret_basic

Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ spec:
port: 4445
endpoint: /clients
forwardedProto: https
tokenEndpointAuthMethod: client_secret_basic
37 changes: 32 additions & 5 deletions hydra/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"

"k8s.io/utils/pointer"
Expand All @@ -21,11 +22,11 @@ const (
schemeHTTP = "http"

testID = "test-id"
testClient = `{"client_id":"test-id","owner":"test-name","scope":"some,scopes","grant_types":["type1"]}`
testClientCreated = `{"client_id":"test-id-2","client_secret":"TmGkvcY7k526","owner":"test-name-2","scope":"some,other,scopes","grant_types":["type2"]}`
testClientUpdated = `{"client_id":"test-id-3","client_secret":"xFoPPm654por","owner":"test-name-3","scope":"yet,another,scope","grant_types":["type3"]}`
testClientList = `{"client_id":"test-id-4","owner":"test-name-4","scope":"scope1 scope2","grant_types":["type4"]}`
testClientList2 = `{"client_id":"test-id-5","owner":"test-name-5","scope":"scope3 scope4","grant_types":["type5"]}`
testClient = `{"client_id":"test-id","owner":"test-name","scope":"some,scopes","grant_types":["type1"],"token_endpoint_auth_method":"client_secret_basic"}`
testClientCreated = `{"client_id":"test-id-2","client_secret":"TmGkvcY7k526","owner":"test-name-2","scope":"some,other,scopes","grant_types":["type2"],"token_endpoint_auth_method":"client_secret_basic"}`
testClientUpdated = `{"client_id":"test-id-3","client_secret":"xFoPPm654por","owner":"test-name-3","scope":"yet,another,scope","grant_types":["type3"],"token_endpoint_auth_method":"client_secret_basic"}`
testClientList = `{"client_id":"test-id-4","owner":"test-name-4","scope":"scope1 scope2","grant_types":["type4"],"token_endpoint_auth_method":"client_secret_basic"}`
testClientList2 = `{"client_id":"test-id-5","owner":"test-name-5","scope":"scope3 scope4","grant_types":["type5"],"token_endpoint_auth_method":"client_secret_basic"}`

statusNotFoundBody = `{"error":"Not Found","error_description":"Unable to locate the requested resource","status_code":404,"request_id":"id"}`
statusConflictBody = `{"error":"Unable to insert or update resource because a resource with that value exists already","error_description":"","status_code":409,"request_id":"id"`
Expand Down Expand Up @@ -171,6 +172,10 @@ func TestCRUD(t *testing.T) {
assert.Equal(testOAuthJSONPost.Owner, o.Owner)
assert.NotNil(o.Secret)
assert.NotNil(o.ClientID)
assert.NotNil(o.TokenEndpointAuthMethod)
if testOAuthJSONPost.TokenEndpointAuthMethod != "" {
assert.Equal(testOAuthJSONPost.TokenEndpointAuthMethod, o.TokenEndpointAuthMethod)
}
}
})
}
Expand Down Expand Up @@ -323,6 +328,28 @@ func TestCRUD(t *testing.T) {
})
}
})

t.Run("default parameters", func(t *testing.T) {
var input = &hydra.OAuth2ClientJSON{
Scope: "some,other,scopes",
GrantTypes: []string{"type2"},
Owner: "test-name-2",
}
assert.Equal(input.TokenEndpointAuthMethod, "")
b, _ := json.Marshal(input)
payload := string(b)
assert.Equal(strings.Index(payload, "token_endpoint_auth_method"), -1)

input = &hydra.OAuth2ClientJSON{
Scope: "some,other,scopes",
GrantTypes: []string{"type2"},
Owner: "test-name-3",
TokenEndpointAuthMethod: "none",
}
b, _ = json.Marshal(input)
payload = string(b)
assert.True(strings.Index(payload, "token_endpoint_auth_method") > 0)
})
}

func runServer(c *hydra.Client, h http.HandlerFunc) {
Expand Down
15 changes: 8 additions & 7 deletions hydra/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import "k8s.io/utils/pointer"

// OAuth2ClientJSON represents an OAuth2 client digestible by ORY Hydra
type OAuth2ClientJSON struct {
ClientID *string `json:"client_id,omitempty"`
Secret *string `json:"client_secret,omitempty"`
GrantTypes []string `json:"grant_types"`
RedirectURIs []string `json:"redirect_uris,omitempty"`
ResponseTypes []string `json:"response_types,omitempty"`
Scope string `json:"scope"`
Owner string `json:"owner"`
ClientID *string `json:"client_id,omitempty"`
Secret *string `json:"client_secret,omitempty"`
GrantTypes []string `json:"grant_types"`
RedirectURIs []string `json:"redirect_uris,omitempty"`
ResponseTypes []string `json:"response_types,omitempty"`
Scope string `json:"scope"`
Owner string `json:"owner"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
}

// Oauth2ClientCredentials represents client ID and password fetched from a Kubernetes secret
Expand Down

0 comments on commit cb8601c

Please sign in to comment.