Skip to content

Commit

Permalink
Merge d8f396a into 5cf3680
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx authored Dec 1, 2023
2 parents 5cf3680 + d8f396a commit 90010fb
Show file tree
Hide file tree
Showing 25 changed files with 1,013 additions and 504 deletions.
13 changes: 7 additions & 6 deletions cmd/mlpa/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ func main() {
IdentityPoolID: env.Get("AWS_RUM_IDENTITY_POOL_ID", ""),
ApplicationID: env.Get("AWS_RUM_APPLICATION_ID", ""),
}
uidBaseURL = env.Get("UID_BASE_URL", "http://mock-uid:8080")
metadataURL = env.Get("ECS_CONTAINER_METADATA_URI_V4", "")
oneloginURL = env.Get("ONELOGIN_URL", "https://home.integration.account.gov.uk")
evidenceBucketName = env.Get("UPLOADS_S3_BUCKET_NAME", "evidence")
eventBusName = env.Get("EVENT_BUS_NAME", "default")
uidBaseURL = env.Get("UID_BASE_URL", "http://mock-uid:8080")
metadataURL = env.Get("ECS_CONTAINER_METADATA_URI_V4", "")
oneloginURL = env.Get("ONELOGIN_URL", "https://home.integration.account.gov.uk")
oneloginIdentityPublicKey = env.Get("ONELOGIN_IDENTITY_PUBLIC_KEY", secrets.GovUkOneLoginIdentityPublicKey)
evidenceBucketName = env.Get("UPLOADS_S3_BUCKET_NAME", "evidence")
eventBusName = env.Get("EVENT_BUS_NAME", "default")
)

staticHash, err := dirhash.HashDir(webDir+"/static", webDir, dirhash.DefaultHash)
Expand Down Expand Up @@ -150,7 +151,7 @@ func main() {

redirectURL := authRedirectBaseURL + page.Paths.AuthRedirect.Format()

signInClient, err := onelogin.Discover(ctx, logger, httpClient, secretsClient, issuer, clientID, redirectURL)
signInClient, err := onelogin.Discover(ctx, logger, httpClient, secretsClient, issuer, clientID, redirectURL, oneloginIdentityPublicKey)
if err != nil {
logger.Fatal(err)
}
Expand Down
34 changes: 16 additions & 18 deletions cmd/mock-onelogin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ import (
"github.com/ministryofjustice/opg-go-common/env"
)

const (
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
signingKid = "my-kid2"
)
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

var (
port = env.Get("PORT", "8080")
Expand All @@ -31,7 +28,8 @@ var (
clientId = env.Get("CLIENT_ID", "theClientId")
serviceRedirectUrl = env.Get("REDIRECT_RUL", "http://localhost:5050/auth/redirect")

signingKey, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
tokenSigningKey, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
tokenSigningKeyID = randomString("key-", 8)

sessions = map[string]sessionData{}
tokens = map[string]sessionData{}
Expand Down Expand Up @@ -76,7 +74,7 @@ func openIDConfig(c OpenIdConfig) http.HandlerFunc {

func jwks() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
publicKey := signingKey.PublicKey
publicKey := tokenSigningKey.PublicKey

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
Expand All @@ -85,7 +83,7 @@ func jwks() http.HandlerFunc {
"kty": "EC",
"use": "sig",
"crv": "P-256",
"kid": signingKid,
"kid": tokenSigningKeyID,
"x": base64.URLEncoding.EncodeToString(publicKey.X.Bytes()),
"y": base64.URLEncoding.EncodeToString(publicKey.Y.Bytes()),
"alg": "ES256",
Expand All @@ -98,7 +96,7 @@ func jwks() http.HandlerFunc {
func token(clientId, issuer string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
code := r.PostFormValue("code")
accessToken := randomString(10)
accessToken := randomString("token-", 10)

session := sessions[code]
delete(sessions, code)
Expand Down Expand Up @@ -150,7 +148,7 @@ func authorize() http.HandlerFunc {

q := u.Query()

code := randomString(10)
code := randomString("code-", 10)
q.Set("code", code)
q.Set("state", r.FormValue("state"))

Expand All @@ -169,7 +167,7 @@ func authorize() http.HandlerFunc {
func userInfo(privateKey *ecdsa.PrivateKey) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userInfo := UserInfoResponse{
Sub: randomString(12),
Sub: randomString("sub-", 12),
Email: "[email protected]",
EmailVerified: true,
Phone: "01406946277",
Expand Down Expand Up @@ -221,14 +219,14 @@ func main() {
JwksURI: internalURL + "/.well-known/jwks",
}

privateKeyBytes, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSVBheDJBYW92aXlQWDF3cndmS2FWckxEOHdQbkpJcUlicTMzZm8rWHdBZDdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSlEyVmtpZWtzNW9rSTIxY1Jma0FhOXVxN0t4TTZtMmpaWUJ4cHJsVVdCWkNFZnhxMjdwVQp0Qzd5aXplVlRiZUVqUnlJaStYalhPQjFBbDhPbHFtaXJnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=")
privateKey, _ := jwt.ParseECPrivateKeyFromPEM(privateKeyBytes)
identityPrivateKeyBytes, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSVBheDJBYW92aXlQWDF3cndmS2FWckxEOHdQbkpJcUlicTMzZm8rWHdBZDdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSlEyVmtpZWtzNW9rSTIxY1Jma0FhOXVxN0t4TTZtMmpaWUJ4cHJsVVdCWkNFZnhxMjdwVQp0Qzd5aXplVlRiZUVqUnlJaStYalhPQjFBbDhPbHFtaXJnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=")
identityPrivateKey, _ := jwt.ParseECPrivateKeyFromPEM(identityPrivateKeyBytes)

http.HandleFunc("/.well-known/openid-configuration", openIDConfig(c))
http.HandleFunc("/.well-known/jwks", jwks())
http.HandleFunc("/authorize", authorize())
http.HandleFunc("/token", token(clientId, c.Issuer))
http.HandleFunc("/userinfo", userInfo(privateKey))
http.HandleFunc("/userinfo", userInfo(identityPrivateKey))

log.Println("GOV UK Sign in mock initialized")

Expand Down Expand Up @@ -256,25 +254,25 @@ func stringWithCharset(length int, charset string) string {
return string(bytes)
}

func randomString(length int) string {
return stringWithCharset(length, charset)
func randomString(prefix string, length int) string {
return prefix + stringWithCharset(length, charset)
}

func createSignedToken(nonce, clientId, issuer string) (string, error) {
t := jwt.New(jwt.SigningMethodES256)

t.Header["kid"] = signingKid
t.Header["kid"] = tokenSigningKeyID

t.Claims = jwt.MapClaims{
"sub": fmt.Sprintf("%s-sub", randomString(10)),
"sub": randomString("sub-", 10),
"iss": issuer,
"nonce": nonce,
"aud": clientId,
"exp": time.Now().Add(time.Minute * 5).Unix(),
"iat": time.Now().Unix(),
}

return t.SignedString(signingKey)
return t.SignedString(tokenSigningKey)
}

func userDetails(key string) (givenName, familyName, birthDate string) {
Expand Down
37 changes: 29 additions & 8 deletions internal/onelogin/client.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package onelogin

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/url"
"time"
Expand Down Expand Up @@ -47,20 +51,22 @@ type Client struct {
secretsClient SecretsClient
randomString func(int) string
jwks *keyfunc.JWKS
identityPublicKey string

clientID string
redirectURL string
}

func Discover(ctx context.Context, logger Logger, httpClient *http.Client, secretsClient SecretsClient, issuer, clientID, redirectURL string) (*Client, error) {
func Discover(ctx context.Context, logger Logger, httpClient *http.Client, secretsClient SecretsClient, issuer, clientID, redirectURL, identityPublicKey string) (*Client, error) {
c := &Client{
ctx: ctx,
logger: logger,
httpClient: httpClient,
secretsClient: secretsClient,
randomString: random.String,
clientID: clientID,
redirectURL: redirectURL,
ctx: ctx,
logger: logger,
httpClient: httpClient,
secretsClient: secretsClient,
randomString: random.String,
identityPublicKey: identityPublicKey,
clientID: clientID,
redirectURL: redirectURL,
}

req, err := http.NewRequest("GET", issuer+openidConfigurationEndpoint, nil)
Expand All @@ -84,6 +90,21 @@ func Discover(ctx context.Context, logger Logger, httpClient *http.Client, secre
RefreshErrorHandler: func(err error) {
c.logger.Print("error refreshing jwks:", err)
},
RequestFactory: func(ctx context.Context, url string) (*http.Request, error) {
log.Println("keyfunc making request, GET", url)
return http.NewRequestWithContext(ctx, http.MethodGet, url, bytes.NewReader(nil))
},
ResponseExtractor: func(ctx context.Context, resp *http.Response) (json.RawMessage, error) {
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%w: %d", keyfunc.ErrInvalidHTTPStatusCode, resp.StatusCode)
}

x, err := io.ReadAll(resp.Body)
log.Println("keyfunc made request", x)

return x, err
},
RefreshInterval: 24 * time.Hour,
RefreshRateLimit: 5 * time.Minute,
RefreshTimeout: 30 * time.Second,
Expand Down
2 changes: 1 addition & 1 deletion internal/onelogin/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestDiscover(t *testing.T) {

expectedConfiguration.JwksURI = oidcServer.URL + "/.well-known/jwks"

c, err := Discover(context.Background(), nil, http.DefaultClient, nil, oidcServer.URL, "client-id", "http://redirect")
c, err := Discover(context.Background(), nil, http.DefaultClient, nil, oidcServer.URL, "client-id", "http://redirect", "secret-key")

assert.Nil(t, err)
assert.Equal(t, expectedConfiguration, c.openidConfiguration)
Expand Down
10 changes: 9 additions & 1 deletion internal/onelogin/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package onelogin

import (
"context"
"crypto/ecdsa"
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"strings"
Expand Down Expand Up @@ -82,6 +84,8 @@ func (c *Client) Exchange(ctx context.Context, code, nonce string) (idToken, acc
return "", "", fmt.Errorf("could not read token body: %w", err)
}

log.Println(tokenResponse.IDToken)

if err := c.validateToken(tokenResponse.IDToken, nonce); err != nil {
return "", "", fmt.Errorf("id token not valid: %w", err)
}
Expand All @@ -90,7 +94,11 @@ func (c *Client) Exchange(ctx context.Context, code, nonce string) (idToken, acc
}

func (c *Client) validateToken(idToken, nonce string) error {
token, err := jwt.ParseWithClaims(idToken, jwt.MapClaims{}, c.jwks.Keyfunc)
token, err := jwt.ParseWithClaims(idToken, jwt.MapClaims{}, func(t *jwt.Token) (any, error) {
k, e := c.jwks.Keyfunc(t)
log.Println(*(k.(*ecdsa.PublicKey)))
return k, e
})
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 90010fb

Please sign in to comment.