This repository has been archived on 2022-07-28. You can view files and clone it, but cannot push or open issues or pull requests.
hydra_oidc_poc/cmd/runapp/main.go
2020-12-29 21:50:59 +01:00

167 lines
4.2 KiB
Go

package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
client2 "github.com/go-openapi/runtime/client"
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jwt"
"golang.org/x/oauth2"
)
var oauth2Config *oauth2.Config
type OpenIDConfiguration struct {
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
JWKSUri string `json:"jwks_uri"`
}
func main() {
headers := map[string][]string{
"Accept": {"application/json"},
}
var body []byte
req, err := http.NewRequest(http.MethodGet, "https://localhost:4444/.well-known/openid-configuration", bytes.NewBuffer(body))
if err != nil {
log.Panic(err)
}
req.Header = headers
client, err := client2.TLSClient(client2.TLSClientOptions{InsecureSkipVerify: true})
if err != nil {
log.Panic(err)
}
resp, err := client.Do(req)
if err != nil {
log.Panic(err)
}
dec := json.NewDecoder(resp.Body)
discoveryResponse := &OpenIDConfiguration{}
err = dec.Decode(discoveryResponse)
if err != nil {
log.Panic(err)
}
oauth2Config = &oauth2.Config{
ClientID: "local-test-app",
ClientSecret: "uzvTqaCvUSBMd0aVjECmD-egAJ",
Endpoint: oauth2.Endpoint{
AuthURL: discoveryResponse.AuthorizationEndpoint,
TokenURL: discoveryResponse.TokenEndpoint,
},
Scopes: []string{"openid", "offline"},
}
http.Handle("/", NewIndexPage())
http.Handle("/callback", NewCallbackHandler(discoveryResponse.JWKSUri))
err = http.ListenAndServe(":4000", http.DefaultServeMux)
if err != nil {
log.Panic(err)
}
}
type callbackHandler struct {
JwksUri string
}
func (c *callbackHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
http.Error(writer, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if request.URL.Path != "/callback" {
http.NotFound(writer, request)
return
}
code := request.URL.Query().Get("code")
scope := request.URL.Query().Get("scope")
state := request.URL.Query().Get("state")
ctx := context.Background()
httpClient, err := client2.TLSClient(client2.TLSClientOptions{InsecureSkipVerify: true})
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
tok, err := oauth2Config.Exchange(ctx, code)
if err != nil {
log.Print(err)
http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
accessToken := tok.AccessToken
refreshToken := tok.RefreshToken
idToken := tok.Extra("id_token")
keySet, err := jwk.FetchHTTP(c.JwksUri, jwk.WithHTTPClient(httpClient))
if err != nil {
log.Print(err)
http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
parsedIdToken, err := jwt.Parse(strings.NewReader(idToken.(string)), jwt.WithKeySet(keySet))
if err != nil {
log.Print(err)
http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
_, err = fmt.Fprintf(
writer,
"scope: %s, state: %s\ncode %s -> token %+v\n\naccess: %+v\nrefresh: %+v\nid: %+v\n\nParsed id token:\n%+v",
code, scope, state, tok, accessToken, refreshToken, idToken, parsedIdToken)
if err != nil {
log.Print(err)
http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
}
func NewCallbackHandler(jwksUri string) *callbackHandler {
return &callbackHandler{JwksUri: jwksUri}
}
type indexHandler struct{}
func (i indexHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
http.Error(writer, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if request.URL.Path != "/" {
http.NotFound(writer, request)
return
}
writer.WriteHeader(http.StatusOK)
writer.Header().Add("Content-Type", "text/html")
_, err := writer.Write([]byte(`
<!DOCTYPE html>
<html lang="en">
<head><title>Auth test</title></head>
<body>
<h1>Hello World</h1>
<a href="https://localhost:4444/oauth2/auth?client_id=local-test-app&response_type=code&scope=openid%20offline&state=12345678">Login</a>
</body>
</html>
`))
if err != nil {
log.Panic(err)
}
}
func NewIndexPage() *indexHandler {
return &indexHandler{}
}