Skip to content

Commit

Permalink
sdk: add wrapper library for HTTP Managers (#130)
Browse files Browse the repository at this point in the history
Signed-off-by: Mohamedh Fazal <mohamedhfazal@gmail.com>
  • Loading branch information
fazal authored and Aeneas committed Jul 3, 2016
1 parent 24d34b3 commit 266b324
Show file tree
Hide file tree
Showing 4 changed files with 427 additions and 0 deletions.
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`

```
// 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 {
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

0 comments on commit 266b324

Please sign in to comment.