fix(controller): Ensure that OAuth2Client reconciliation creates hydra client for specs (#83)

This commit is contained in:
Alexandre Mclean
2021-09-14 08:07:06 -04:00
committed by GitHub
parent 273922d2e2
commit 028c3df4c2
8 changed files with 242 additions and 156 deletions

View File

@ -8,15 +8,51 @@ import (
"net/http"
"net/url"
"path"
hydrav1alpha1 "github.com/ory/hydra-maester/api/v1alpha1"
"github.com/ory/hydra-maester/helpers"
)
type Client struct {
type Client interface {
GetOAuth2Client(id string) (*OAuth2ClientJSON, bool, error)
ListOAuth2Client() ([]*OAuth2ClientJSON, error)
PostOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error)
PutOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error)
DeleteOAuth2Client(id string) error
}
type InternalClient struct {
HydraURL url.URL
HTTPClient *http.Client
ForwardedProto string
}
func (c *Client) GetOAuth2Client(id string) (*OAuth2ClientJSON, bool, error) {
// New returns a new hydra InternalClient instance.
func New(spec hydrav1alpha1.OAuth2ClientSpec, tlsTrustStore string, insecureSkipVerify bool) (Client, error) {
address := fmt.Sprintf("%s:%d", spec.HydraAdmin.URL, spec.HydraAdmin.Port)
u, err := url.Parse(address)
if err != nil {
return nil, err
}
c, err := helpers.CreateHttpClient(insecureSkipVerify, tlsTrustStore)
if err != nil {
return nil, err
}
client := &InternalClient{
HydraURL: *u.ResolveReference(&url.URL{Path: spec.HydraAdmin.Endpoint}),
HTTPClient: c,
}
if spec.HydraAdmin.ForwardedProto != "" && spec.HydraAdmin.ForwardedProto != "off" {
client.ForwardedProto = spec.HydraAdmin.ForwardedProto
}
return client, nil
}
func (c *InternalClient) GetOAuth2Client(id string) (*OAuth2ClientJSON, bool, error) {
var jsonClient *OAuth2ClientJSON
@ -40,7 +76,7 @@ func (c *Client) GetOAuth2Client(id string) (*OAuth2ClientJSON, bool, error) {
}
}
func (c *Client) ListOAuth2Client() ([]*OAuth2ClientJSON, error) {
func (c *InternalClient) ListOAuth2Client() ([]*OAuth2ClientJSON, error) {
var jsonClientList []*OAuth2ClientJSON
@ -62,7 +98,7 @@ func (c *Client) ListOAuth2Client() ([]*OAuth2ClientJSON, error) {
}
}
func (c *Client) PostOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error) {
func (c *InternalClient) PostOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error) {
var jsonClient *OAuth2ClientJSON
@ -86,7 +122,7 @@ func (c *Client) PostOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error
}
}
func (c *Client) PutOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error) {
func (c *InternalClient) PutOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error) {
var jsonClient *OAuth2ClientJSON
@ -107,7 +143,7 @@ func (c *Client) PutOAuth2Client(o *OAuth2ClientJSON) (*OAuth2ClientJSON, error)
return jsonClient, nil
}
func (c *Client) DeleteOAuth2Client(id string) error {
func (c *InternalClient) DeleteOAuth2Client(id string) error {
req, err := c.newRequest(http.MethodDelete, id, nil)
if err != nil {
@ -123,14 +159,14 @@ func (c *Client) DeleteOAuth2Client(id string) error {
case http.StatusNoContent:
return nil
case http.StatusNotFound:
fmt.Printf("client with id %s does not exist", id)
fmt.Printf("InternalClient with id %s does not exist", id)
return nil
default:
return fmt.Errorf("%s %s http request returned unexpected status code %s", req.Method, req.URL.String(), resp.Status)
}
}
func (c *Client) newRequest(method, relativePath string, body interface{}) (*http.Request, error) {
func (c *InternalClient) newRequest(method, relativePath string, body interface{}) (*http.Request, error) {
var buf io.ReadWriter
if body != nil {
@ -162,7 +198,7 @@ func (c *Client) newRequest(method, relativePath string, body interface{}) (*htt
}
func (c *Client) do(req *http.Request, v interface{}) (*http.Response, error) {
func (c *InternalClient) do(req *http.Request, v interface{}) (*http.Response, error) {
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err

View File

@ -12,9 +12,10 @@ import (
"k8s.io/utils/pointer"
"github.com/ory/hydra-maester/hydra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ory/hydra-maester/hydra"
)
const (
@ -60,7 +61,7 @@ func TestCRUD(t *testing.T) {
assert := assert.New(t)
c := hydra.Client{
c := hydra.InternalClient{
HTTPClient: &http.Client{},
HydraURL: url.URL{Scheme: schemeHTTP},
}
@ -397,7 +398,7 @@ func TestCRUD(t *testing.T) {
})
}
func runServer(c *hydra.Client, h http.HandlerFunc) {
func runServer(c *hydra.InternalClient, h http.HandlerFunc) {
s := httptest.NewServer(h)
serverUrl, _ := url.Parse(s.URL)
c.HydraURL = *serverUrl.ResolveReference(&url.URL{Path: clientsEndpoint})

View File

@ -2,8 +2,12 @@ package hydra
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"k8s.io/utils/pointer"
hydrav1alpha1 "github.com/ory/hydra-maester/api/v1alpha1"
)
// OAuth2ClientJSON represents an OAuth2 client digestible by ORY Hydra
@ -23,7 +27,8 @@ type OAuth2ClientJSON struct {
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// Oauth2ClientCredentials represents client ID and password fetched from a Kubernetes secret
// Oauth2ClientCredentials represents client ID and password fetched from a
// Kubernetes secret
type Oauth2ClientCredentials struct {
ID []byte
Password []byte
@ -36,3 +41,49 @@ func (oj *OAuth2ClientJSON) WithCredentials(credentials *Oauth2ClientCredentials
}
return oj
}
// FromOAuth2Client converts an OAuth2Client into a OAuth2ClientJSON object that represents an OAuth2 InternalClient digestible by ORY Hydra
func FromOAuth2Client(c *hydrav1alpha1.OAuth2Client) (*OAuth2ClientJSON, error) {
meta, err := json.Marshal(c.Spec.Metadata)
if err != nil {
return nil, errors.WithMessage(err, "unable to encode `metadata` property value to json")
}
return &OAuth2ClientJSON{
ClientName: c.Spec.ClientName,
GrantTypes: grantToStringSlice(c.Spec.GrantTypes),
ResponseTypes: responseToStringSlice(c.Spec.ResponseTypes),
RedirectURIs: redirectToStringSlice(c.Spec.RedirectURIs),
PostLogoutRedirectURIs: redirectToStringSlice(c.Spec.PostLogoutRedirectURIs),
AllowedCorsOrigins: redirectToStringSlice(c.Spec.AllowedCorsOrigins),
Audience: c.Spec.Audience,
Scope: c.Spec.Scope,
Owner: fmt.Sprintf("%s/%s", c.Name, c.Namespace),
TokenEndpointAuthMethod: string(c.Spec.TokenEndpointAuthMethod),
Metadata: meta,
}, nil
}
func responseToStringSlice(rt []hydrav1alpha1.ResponseType) []string {
var output = make([]string, len(rt))
for i, elem := range rt {
output[i] = string(elem)
}
return output
}
func grantToStringSlice(gt []hydrav1alpha1.GrantType) []string {
var output = make([]string, len(gt))
for i, elem := range gt {
output[i] = string(elem)
}
return output
}
func redirectToStringSlice(ru []hydrav1alpha1.RedirectURI) []string {
var output = make([]string, len(ru))
for i, elem := range ru {
output[i] = string(elem)
}
return output
}