Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wrapper library for HTTP Managers #130

Merged
merged 17 commits into from
Jul 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,136 @@ Or by specifying the following flags:

You can do so by running `hydra host --force-dangerous-http`.

### How do I use it in my application?

Hydra already comes with HTTP Managers. You could use directly by importing the following or use the thin wrapper created in `ory-am/hydra/sdk`

#### Using HTTP Managers

**Manage OAuth Clients**
`ory-am/hydra/client.HTTPManager`

**Manage SSO Connections**
`ory-am/hydra/connection.HTTPManager`

**Manage Policies**
`ory-am/hydra/policy.HTTPManager`

**Manage JWK**
`ory-am/hydra/jwk.HTTPManager`

**Use Warden**
`ory-am/hydra/warden.HTTPWarden`

#### Using SDK

**Connect to Hydra.**
```
client, err := sdk.Connect(
sdk.ClientID("client-id"),
sdk.ClientSecret("client-secret"),
sdk.ClustURL("https://localhost:4444"),
)
```
**Use the API**

**OAuth Clients**: `client.Client`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add examples here? e.g.

// client, err := ...
oauth2Client, err := client.Client.GetClient("1234")


```
// To create a new OAuth2 client
newClient, err := client.Client.CreateClient(&client.Client{
ID: "deadbeef",
Secret: "sup3rs3cret",
RedirectURIs: []string{"http://yourapp/callback"},
// ...
})

// Retrieve newly created client
newClient, err = client.Client.GetClient(newClient.ID)

// To remove newly created client
err = client.Client.DeleteClient(newClient.ID)

// Retrieve list of all clients
clients, err := client.Client.GetClients()
```


**SSO Connections**: `client.SSO`

```
// Create a new connection
newSSOConn, err := client.SSO.Create(&connection.Connection{
Provider: "login.google.com",
LocalSubject: "bob",
RemoteSubject: "googleSubjectID",
})

// Retrieve newly created connection
ssoConn, err := client.SSO.Get(newSSOConn.ID)

// Delete connection
ssoConn, err := client.SSO.Delete(newSSOConn.ID)

// Find a connection by subject
ssoConns, err := client.SSO.FindAllByLocalSubject("bob")
ssoConns, err := client.SSO.FindByRemoteSubject("login.google.com", "googleSubjectID")
```

**Policiess**: `client.Policy`

```
// Create a new policy
// allow user to view his/her own photos
newPolicy, err := client.Policy.Create(ladon.DefaultPolicy{
ID: "1234", // ID is not required
Subjects: []string{"bob"},
Resources: []string{"urn:media:images"},
Actions: []string{"get", "find"},
Effect: ladon.AllowAccess,
Conditions: ladon.Conditions{
"owner": &ladon.EqualSubjectCondition{},
}
})

// Retrieve a stored policy
policy, err := client.Policy.Get("1234")

// Delete a policy
err := client.Policy.Delete("1234")

// Retrieve all policies for a subject
policies, err := client.Policy.FindPoliciesForSubject("bob")
```

**JWK**: `client.JWK`

```
// Generate new key set
keySet, err := client.JWK.CreateKeys("app-tls-keys", "HS256")

// Retrieve key set
keySet, err := client.JWK.GetKeySet("app-tls-keys")

// Delete key set
err := client.JWK.DeleteKeySet("app-tls-keys")
```

**Warden**: `client.Warden`

```
// Check if action is allowed
client.Warden.HTTPActionAllowed(ctx, req, &ladon.Request{
Resource: "urn:media:images",
Action: "get",
Subject: "bob",
}, "media.images")

// Check if request is authorized
client.Warden.HTTPAuthorized(ctx, req, "media.images")

```

## Hall of Fame

A list of extraordinary contributors and [bug hunters](https://github.com/ory-am/hydra/issues/84).
Expand Down
129 changes: 129 additions & 0 deletions sdk/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Wraps hydra HTTP Manager's
package sdk

import (
"crypto/tls"
"net/http"
"net/url"
"os"

"github.com/ory-am/hydra/client"
"github.com/ory-am/hydra/connection"
"github.com/ory-am/hydra/jwk"
"github.com/ory-am/hydra/pkg"
"github.com/ory-am/hydra/policy"
"github.com/ory-am/hydra/warden"

"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
)

type Client struct {
http *http.Client
clusterURL *url.URL
clientID string
clientSecret string
skipTLSVerify bool
scopes []string

credentials clientcredentials.Config

Client *client.HTTPManager
SSO *connection.HTTPManager
JWK *jwk.HTTPManager
Policies *policy.HTTPManager
Warden *warden.HTTPWarden
}

type option func(*Client) error

// default options for hydra client
var defaultOptions = []option{
ClusterURL(os.Getenv("HYDRA_CLUSTER_URL")),
ClientID(os.Getenv("HYDRA_CLIENT_ID")),
ClientSecret(os.Getenv("HYDRA_CLIENT_SECRET")),
Scopes("core", "hydra"),
}

// Connect instantiates a new client to communicate with Hydra
func Connect(opts ...option) (*Client, error) {
c := &Client{}

var err error
// apply default options
for _, opt := range defaultOptions {
err = opt(c)
if err != nil {
return nil, err
}
}

// override any default values with given options
for _, opt := range opts {
err = opt(c)
if err != nil {
return nil, err
}
}

c.credentials = clientcredentials.Config{
ClientID: c.clientID,
ClientSecret: c.clientSecret,
TokenURL: pkg.JoinURL(c.clusterURL, "oauth2/token").String(),
Scopes: c.scopes,
}

c.http = http.DefaultClient

if c.skipTLSVerify {
c.http = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
}

err = c.authenticate()
if err != nil {
return nil, err
}

// initialize service endpoints
c.Client = &client.HTTPManager{
Endpoint: pkg.JoinURL(c.clusterURL, "/clients"),
Client: c.http,
}

c.SSO = &connection.HTTPManager{
Endpoint: pkg.JoinURL(c.clusterURL, "/connections"),
Client: c.http,
}

c.JWK = &jwk.HTTPManager{
Endpoint: pkg.JoinURL(c.clusterURL, "/keys"),
Client: c.http,
}

c.Policies = &policy.HTTPManager{
Endpoint: pkg.JoinURL(c.clusterURL, "/policies"),
Client: c.http,
}

c.Warden = &warden.HTTPWarden{
Client: c.http,
}

return c, nil
}

func (h *Client) authenticate() error {
ctx := context.WithValue(oauth2.NoContext, oauth2.HTTPClient, h.http)
_, err := h.credentials.Token(ctx)
if err != nil {
return err
}

h.http = h.credentials.Client(ctx)
return nil
}
83 changes: 83 additions & 0 deletions sdk/client_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package sdk

import (
"io/ioutil"
"net/url"

"gopkg.in/yaml.v1"
)

// ClusterURL sets Hydra service URL
func ClusterURL(urlStr string) option {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please document exported functions :)

return func(c *Client) error {
var err error
c.clusterURL, err = url.Parse(urlStr)
return err
}
}

type hydraConfig struct {
ClusterURL string `yaml:"cluster_url"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
}

// FromYAML loads configurations from a YAML file
func FromYAML(file string) option {
return func(c *Client) error {
var err error
var config = hydraConfig{}

data, err := ioutil.ReadFile(file)
if err != nil {
return err
}

err = yaml.Unmarshal(data, &config)
if err != nil {
return err
}

c.clusterURL, err = url.Parse(config.ClusterURL)
if err != nil {
return err
}

c.clientID = config.ClientID
c.clientSecret = config.ClientSecret

return nil
}
}

// ClientID sets OAuth client ID
func ClientID(id string) option {
return func(c *Client) error {
c.clientID = id
return nil
}
}

// ClientSecret sets OAuth client secret
func ClientSecret(secret string) option {
return func(c *Client) error {
c.clientSecret = secret
return nil
}
}

// SkipTLSVerify skips TLS verification
func SkipTLSVerify() option {
return func(c *Client) error {
c.skipTLSVerify = true
return nil
}
}

// Scopes sets client scopes granted by Hydra
func Scopes(scopes ...string) option {
return func(c *Client) error {
c.scopes = scopes
return nil
}
}
Loading