Skip to content
This repository has been archived by the owner on Dec 1, 2021. It is now read-only.

Commit

Permalink
Merge pull request #3 from XenitAB/split-out-packages
Browse files Browse the repository at this point in the history
split out packages
  • Loading branch information
simongottschlag committed Jul 14, 2021
2 parents c3a2a92 + 9339e63 commit 73c2911
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 218 deletions.
48 changes: 48 additions & 0 deletions authority/authority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package authority

import (
"fmt"
"sync"
)

type Options struct {
Issuer string
}

func (opts Options) Validate() error {
if opts.Issuer == "" {
return fmt.Errorf("Issuer is empty")
}

return nil
}

type handler struct {
sync.RWMutex
issuer string
}

func NewHandler(opts Options) (*handler, error) {
err := opts.Validate()
if err != nil {
return nil, err
}

return &handler{
issuer: opts.Issuer,
}, nil
}

func (h *handler) GetIssuer() string {
h.RLock()
defer h.RUnlock()

return h.issuer
}

func (h *handler) SetIssuer(newIssuer string) {
h.Lock()
defer h.Unlock()

h.issuer = newIssuer
}
35 changes: 26 additions & 9 deletions server/jwk.go → key/key.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package server
package key

import (
"crypto"
Expand All @@ -9,43 +9,60 @@ import (

"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
"github.com/xenitab/dispans/models"
)

func newKeys() (jwk.Key, jwk.Key, error) {
type handler struct {
privateKey models.PrivateKey
publicKey models.PublicKey
}

func NewHandler() (*handler, error) {
ecdsaKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil {
fmt.Printf("failed to generate new ECDSA privatre key: %s\n", err)
return nil, nil, err
return nil, err
}

key, err := jwk.New(ecdsaKey)
if err != nil {
return nil, nil, err
return nil, err
}

if _, ok := key.(jwk.ECDSAPrivateKey); !ok {
return nil, nil, fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key)
return nil, fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key)
}

thumbprint, err := key.Thumbprint(crypto.SHA256)
if err != nil {
return nil, nil, err
return nil, err
}

keyID := fmt.Sprintf("%x", thumbprint)
key.Set(jwk.KeyIDKey, keyID)

pubKey, err := jwk.New(ecdsaKey.PublicKey)
if err != nil {
return nil, nil, err
return nil, err
}

if _, ok := pubKey.(jwk.ECDSAPublicKey); !ok {
return nil, nil, fmt.Errorf("expected jwk.ECDSAPublicKey, got %T", key)
return nil, fmt.Errorf("expected jwk.ECDSAPublicKey, got %T", key)
}

pubKey.Set(jwk.KeyIDKey, keyID)
pubKey.Set(jwk.AlgorithmKey, jwa.ES384)

return key, pubKey, nil
return &handler{
privateKey: key,
publicKey: pubKey,
}, nil
}

func (h *handler) GetPrivateKey() models.PrivateKey {
return h.privateKey
}

func (h *handler) GetPublicKey() models.PublicKey {
return h.publicKey
}
14 changes: 14 additions & 0 deletions models/authority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package models

type IssuerGetter interface {
GetIssuer() string
}

type IssuerSetter interface {
SetIssuer(newIssuer string)
}

type IssuerGetSetter interface {
IssuerGetter
IssuerSetter
}
19 changes: 19 additions & 0 deletions models/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package models

import "github.com/lestrrat-go/jwx/jwk"

type PrivateKey jwk.Key
type PublicKey jwk.Key

type PrivateKeyGetter interface {
GetPrivateKey() PrivateKey
}

type PublicKeyGetter interface {
GetPublicKey() PublicKey
}

type KeysGetter interface {
PrivateKeyGetter
PublicKeyGetter
}
20 changes: 20 additions & 0 deletions models/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package models

import (
"context"

asoauth2 "github.com/go-oauth2/oauth2/v4"
)

type AccessTokenGetter interface {
Token(ctx context.Context, data *asoauth2.GenerateBasic, isGenRefresh bool) (string, string, error)
}

type ExtensionsFieldsGetter interface {
ExtensionFieldsHandler(ti asoauth2.TokenInfo) map[string]interface{}
}

type TokenGetter interface {
AccessTokenGetter
ExtensionsFieldsGetter
}
18 changes: 4 additions & 14 deletions server/user.go → models/user.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package server
package models

type User struct {
UserID string `json:"sub"`
Expand All @@ -10,18 +10,8 @@ type User struct {
Locale string `json:"locale,omitempty"`
}

func GetUserByID(userID string) (User, error) {
return User{
UserID: userID,
Email: "test@test.com",
EmailVerified: boolPtr(true),
Name: "test testsson",
FamilyName: "testsson",
GivenName: "test",
Locale: "US",
}, nil
}
type Users map[string]User

func boolPtr(b bool) *bool {
return &b
type UserGetter interface {
GetUserByID(userID string) (User, error)
}
44 changes: 22 additions & 22 deletions server/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,35 @@ import (

asserver "github.com/go-oauth2/oauth2/v4/server"
"github.com/go-session/session"
"github.com/lestrrat-go/jwx/jwk"
"github.com/xenitab/dispans/models"
)

type HandlersOptions struct {
AuthorizationServer *asserver.Server
PublicKey jwk.Key
Issuer string
PublicKeyHandler models.PublicKeyGetter
IssuerHandler models.IssuerGetter
}

func (opts HandlersOptions) Validate() error {
if opts.AuthorizationServer == nil {
return fmt.Errorf("AuthorizationServer is nil")
}

if opts.PublicKey == nil {
return fmt.Errorf("PublicKey is nil")
if opts.PublicKeyHandler == nil {
return fmt.Errorf("PublicKeyHandler is nil")
}

if opts.Issuer == "" {
return fmt.Errorf("Issuer is empty")
if opts.IssuerHandler == nil {
return fmt.Errorf("IssuerHandler is nil")
}

return nil
}

type handlers struct {
as *asserver.Server
publicKey jwk.Key
issuer string
as *asserver.Server
publicKeyHandler models.PublicKeyGetter
issuerHandler models.IssuerGetter
}

func newHandlers(opts HandlersOptions) (*handlers, error) {
Expand All @@ -48,9 +48,9 @@ func newHandlers(opts HandlersOptions) (*handlers, error) {
}

return &handlers{
as: opts.AuthorizationServer,
publicKey: opts.PublicKey,
issuer: opts.Issuer,
as: opts.AuthorizationServer,
publicKeyHandler: opts.PublicKeyHandler,
issuerHandler: opts.IssuerHandler,
}, nil
}

Expand Down Expand Up @@ -138,17 +138,21 @@ func (h *handlers) test(w http.ResponseWriter, r *http.Request) {
func (h *handlers) jwk(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

pubKey := h.publicKeyHandler.GetPublicKey()

e := json.NewEncoder(w)
e.SetIndent("", " ")
e.Encode(h.publicKey)
e.Encode(pubKey)
}

func (h *handlers) discovery(w http.ResponseWriter, r *http.Request) {
issuer := h.issuerHandler.GetIssuer()

discoveryData := map[string]interface{}{
"issuer": h.issuer,
"authorization_endpoint": h.issuer + "/oauth/authorize",
"token_endpoint": h.issuer + "/oauth/token",
"jwks_uri": h.issuer + "/jwk",
"issuer": issuer,
"authorization_endpoint": issuer + "/oauth/authorize",
"token_endpoint": issuer + "/oauth/token",
"jwks_uri": issuer + "/jwk",
"response_types_supported": []string{"code"},
"subject_types_supported": []string{"public"},
"id_token_signing_alg_values_supported": []string{"ES384"},
Expand Down Expand Up @@ -176,7 +180,3 @@ func (h *handlers) serveHTML(w http.ResponseWriter, req *http.Request, filename
req.URL.Path = filename
handler.ServeHTTP(w, req)
}

func (h *handlers) SetIssuer(newIssuer string) {
h.issuer = newIssuer
}
26 changes: 16 additions & 10 deletions server/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jwt"
"github.com/stretchr/testify/require"
"github.com/xenitab/dispans/authority"
"github.com/xenitab/dispans/key"
)

const (
Expand Down Expand Up @@ -192,7 +194,7 @@ func TestJwk(t *testing.T) {
accessToken, err := jwt.Parse([]byte(tokenResponse.AccessToken), jwt.WithKeySet(keySet))
require.NoError(t, err)

require.Equal(t, handlers.issuer, accessToken.Issuer())
require.Equal(t, handlers.issuerHandler.GetIssuer(), accessToken.Issuer())
require.Equal(t, testClientID, accessToken.Audience()[0])
require.Equal(t, testUsername, accessToken.Subject())
require.WithinDuration(t, time.Now(), accessToken.NotBefore(), 1*time.Second)
Expand All @@ -201,7 +203,7 @@ func TestJwk(t *testing.T) {
idToken, err := jwt.Parse([]byte(tokenResponse.IDToken), jwt.WithKeySet(keySet))
require.NoError(t, err)

require.Equal(t, handlers.issuer, idToken.Issuer())
require.Equal(t, handlers.issuerHandler.GetIssuer(), idToken.Issuer())
require.Equal(t, testClientID, idToken.Audience()[0])
require.Equal(t, testUsername, idToken.Subject())
require.Equal(t, "test testsson", idToken.PrivateClaims()["name"])
Expand Down Expand Up @@ -235,7 +237,7 @@ func TestDiscovery(t *testing.T) {
err = json.Unmarshal(bodyBytes, &discoveryData)
require.NoError(t, err)

require.Equal(t, handlers.issuer, discoveryData.Issuer)
require.Equal(t, handlers.issuerHandler.GetIssuer(), discoveryData.Issuer)
require.Contains(t, discoveryData.JwksUri, "/jwk")
}

Expand Down Expand Up @@ -355,23 +357,27 @@ func testNewHandlers(t *testing.T) *handlers {
RedirectURI: testRedirectURI,
}

priv, pub, err := newKeys()
keyHandler, err := key.NewHandler()
require.NoError(t, err)

srv := &serverHandler{
privateKey: priv,
publicKey: pub,
keyHandler: keyHandler,
}

issuer := "http://test.foo"
authorityOpts := authority.Options{
Issuer: "http://test.foo",
}

authorityHandler, err := authority.NewHandler(authorityOpts)
require.NoError(t, err)

as, err := srv.newAS(opts, issuer)
as, err := srv.newAS(opts, authorityHandler)
require.NoError(t, err)

handlersOpts := HandlersOptions{
AuthorizationServer: as,
PublicKey: srv.publicKey,
Issuer: issuer,
PublicKeyHandler: keyHandler,
IssuerHandler: authorityHandler,
}

handlers, err := newHandlers(handlersOpts)
Expand Down
Loading

0 comments on commit 73c2911

Please sign in to comment.