Refactored login page and process

This commit is contained in:
David J. Allen 2024-04-23 13:17:41 -06:00
parent 61a35c165d
commit 6d2f488a6b
No known key found for this signature in database
GPG key ID: 717C593FF60A2ACC
8 changed files with 179 additions and 160 deletions

View file

@ -2,12 +2,9 @@ package cmd
import ( import (
opaal "davidallendj/opaal/internal" opaal "davidallendj/opaal/internal"
cache "davidallendj/opaal/internal/cache/sqlite"
"davidallendj/opaal/internal/oauth" "davidallendj/opaal/internal/oauth"
"davidallendj/opaal/internal/oidc"
"fmt" "fmt"
"os" "os"
"slices"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -25,73 +22,68 @@ var loginCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
for { for {
// try and find client with valid identity provider config // try and find client with valid identity provider config
var provider *oidc.IdentityProvider // var provider *oidc.IdentityProvider
if target != "" { // if target != "" {
// only try to use client with name give // // only try to use client with name give
index := slices.IndexFunc(config.Authentication.Clients, func(c oauth.Client) bool { // index := slices.IndexFunc(config.Authentication.Clients, func(c oauth.Client) bool {
return target == c.Name // return target == c.Name
}) // })
if index < 0 { // if index < 0 {
fmt.Printf("could not find the target client listed by name") // fmt.Printf("could not find the target client listed by name")
os.Exit(1) // os.Exit(1)
} // }
client := config.Authentication.Clients[index] // client := config.Authentication.Clients[index]
_, err := cache.GetIdentityProvider(config.Options.CachePath, client.Issuer) // _, err := cache.GetIdentityProvider(config.Options.CachePath, client.Issuer)
if err != nil { // if err != nil {
} // }
} else if targetIndex >= 0 { // } else if targetIndex >= 0 {
// only try to use client by index // // only try to use client by index
targetCount := len(config.Authentication.Clients) - 1 // targetCount := len(config.Authentication.Clients) - 1
if targetIndex > targetCount { // if targetIndex > targetCount {
fmt.Printf("target index out of range (found %d)", targetCount) // fmt.Printf("target index out of range (found %d)", targetCount)
} // }
client := config.Authentication.Clients[targetIndex] // client := config.Authentication.Clients[targetIndex]
_, err := cache.GetIdentityProvider(config.Options.CachePath, client.Issuer) // _, err := cache.GetIdentityProvider(config.Options.CachePath, client.Issuer)
if err != nil { // if err != nil {
} // }
} else { // } else {
for _, c := range config.Authentication.Clients { // for _, c := range config.Authentication.Clients {
// try to get identity provider info locally first // // try to get identity provider info locally first
_, err := cache.GetIdentityProvider(config.Options.CachePath, c.Issuer) // _, err := cache.GetIdentityProvider(config.Options.CachePath, c.Issuer)
if err != nil && !config.Options.CacheOnly { // if err != nil && !config.Options.CacheOnly {
fmt.Printf("fetching config from issuer: %v\n", c.Issuer) // fmt.Printf("fetching config from issuer: %v\n", c.Issuer)
// try to get info remotely by fetching // // try to get info remotely by fetching
provider, err = oidc.FetchServerConfig(c.Issuer) // provider, err = oidc.FetchServerConfig(c.Issuer)
if err != nil { // if err != nil {
fmt.Printf("failed to fetch server config: %v\n", err) // fmt.Printf("failed to fetch server config: %v\n", err)
continue // continue
} // }
client = c // client = c
// fetch the provider's JWKS // // fetch the provider's JWKS
err := provider.FetchJwks() // err := provider.FetchJwks()
if err != nil { // if err != nil {
fmt.Printf("failed to fetch JWKS: %v\n", err) // fmt.Printf("failed to fetch JWKS: %v\n", err)
} // }
break // break
} // }
// only test the first if --run-all flag is not set // // only test the first if --run-all flag is not set
if !config.Authentication.TestAllClients { // if !config.Authentication.TestAllClients {
fmt.Printf("stopping after first test...\n\n\n") // fmt.Printf("stopping after first test...\n\n\n")
break // break
} // }
} // }
} // }
if provider == nil { // if provider == nil {
fmt.Printf("failed to retrieve provider config\n") // fmt.Printf("failed to retrieve provider config\n")
os.Exit(1) // os.Exit(1)
} // }
// use clients to make SSO buttons that
for _, client := range config.Authentication.Clients {
MakeButton()
}
// start the listener // start the listener
err := opaal.Login(&config, &client, provider) err := opaal.Login(&config)
if err != nil { if err != nil {
fmt.Printf("%v\n", err) fmt.Printf("%v\n", err)
os.Exit(1) os.Exit(1)

View file

@ -4,7 +4,6 @@ import (
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"davidallendj/opaal/internal/oauth" "davidallendj/opaal/internal/oauth"
"davidallendj/opaal/internal/oidc"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -19,14 +18,14 @@ import (
) )
type JwtBearerFlowParams struct { type JwtBearerFlowParams struct {
AccessToken string AccessToken string
IdToken string IdToken string
IdentityProvider *oidc.IdentityProvider // IdentityProvider *oidc.IdentityProvider
TrustedIssuer *oauth.TrustedIssuer TrustedIssuer *oauth.TrustedIssuer
Client *oauth.Client Client *oauth.Client
Refresh bool Refresh bool
Verbose bool Verbose bool
KeyPath string KeyPath string
} }
type JwtBearerFlowEndpoints struct { type JwtBearerFlowEndpoints struct {
@ -39,22 +38,27 @@ type JwtBearerFlowEndpoints struct {
func NewJwtBearerFlow(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) (string, error) { func NewJwtBearerFlow(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) (string, error) {
// 1. verify that the JWT from the issuer is valid using all keys // 1. verify that the JWT from the issuer is valid using all keys
var ( var (
idp = params.IdentityProvider // idp = params.IdentityProvider
accessToken = params.AccessToken accessToken = params.AccessToken
idToken = params.IdToken idToken = params.IdToken
client = params.Client client = params.Client
trustedIssuer = params.TrustedIssuer trustedIssuer = params.TrustedIssuer
verbose = params.Verbose verbose = params.Verbose
) )
// pre-condition checks to make sure certain variables are set
if client == nil {
return "", fmt.Errorf("invalid client (client is nil)")
}
if accessToken != "" { if accessToken != "" {
_, err := jws.Verify([]byte(accessToken), jws.WithKeySet(idp.KeySet), jws.WithValidateKey(true)) _, err := jws.Verify([]byte(accessToken), jws.WithKeySet(client.Provider.KeySet), jws.WithValidateKey(true))
if err != nil { if err != nil {
return "", fmt.Errorf("failed to verify access token: %v", err) return "", fmt.Errorf("failed to verify access token: %v", err)
} }
} }
if idToken != "" { if idToken != "" {
_, err := jws.Verify([]byte(idToken), jws.WithKeySet(idp.KeySet), jws.WithValidateKey(true)) _, err := jws.Verify([]byte(idToken), jws.WithKeySet(client.Provider.KeySet), jws.WithValidateKey(true))
if err != nil { if err != nil {
return "", fmt.Errorf("failed to verify ID token: %v", err) return "", fmt.Errorf("failed to verify ID token: %v", err)
} }
@ -126,7 +130,7 @@ func NewJwtBearerFlow(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) (s
// TODO: add trusted issuer to cache if successful // TODO: add trusted issuer to cache if successful
// 4. create a new JWT based on the claims from the identity provider and sign // 4. create a new JWT based on the claims from the identity provider and sign
parsedIdToken, err := jwt.ParseString(idToken, jwt.WithKeySet(idp.KeySet)) parsedIdToken, err := jwt.ParseString(idToken, jwt.WithKeySet(client.Provider.KeySet))
if err != nil { if err != nil {
return "", fmt.Errorf("failed to parse ID token: %v", err) return "", fmt.Errorf("failed to parse ID token: %v", err)
} }
@ -242,7 +246,7 @@ func ForwardToken(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) error
var ( var (
client = params.Client client = params.Client
idToken = params.IdToken idToken = params.IdToken
idp = params.IdentityProvider // idp = params.IdentityProvider
verbose = params.Verbose verbose = params.Verbose
) )
@ -250,7 +254,7 @@ func ForwardToken(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) error
if verbose { if verbose {
fmt.Printf("Fetching JWKS from authentication server for verification...\n") fmt.Printf("Fetching JWKS from authentication server for verification...\n")
} }
err := idp.FetchJwks() err := client.Provider.FetchJwks()
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch JWK: %v", err) return fmt.Errorf("failed to fetch JWK: %v", err)
} else { } else {
@ -260,7 +264,7 @@ func ForwardToken(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) error
} }
ti := &oauth.TrustedIssuer{ ti := &oauth.TrustedIssuer{
Issuer: idp.Issuer, Issuer: client.Provider.Issuer,
Subject: "1", Subject: "1",
ExpiresAt: time.Now().Add(time.Second * 3600), ExpiresAt: time.Now().Add(time.Second * 3600),
} }

View file

@ -12,19 +12,11 @@ import (
"time" "time"
) )
func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider) error { func Login(config *Config) error {
if config == nil { if config == nil {
return fmt.Errorf("invalid config") return fmt.Errorf("invalid config")
} }
if client == nil {
return fmt.Errorf("invalid client")
}
if provider == nil {
return fmt.Errorf("invalid identity provider")
}
// make cache if it's not where expect // make cache if it's not where expect
_, err := cache.CreateIdentityProvidersIfNotExists(config.Options.CachePath) _, err := cache.CreateIdentityProvidersIfNotExists(config.Options.CachePath)
if err != nil { if err != nil {
@ -39,18 +31,12 @@ func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider
} }
// print the authorization URL for sharing // print the authorization URL for sharing
var authorizationUrl = client.BuildAuthorizationUrl(provider.Endpoints.Authorization, state)
s := NewServerWithConfig(config) s := NewServerWithConfig(config)
fmt.Printf("Login with external identity provider:\n\n %s/login\n %s\n\n", s.State = state
s.GetListenAddr(), authorizationUrl,
)
var button = MakeButton(authorizationUrl, "Login with "+client.Name)
var authzClient = oauth.NewClient() var authzClient = oauth.NewClient()
authzClient.Scope = config.Authorization.Token.Scope authzClient.Scope = config.Authorization.Token.Scope
// authorize oauth client and listen for callback from provider
fmt.Printf("Waiting for authorization code redirect @%s/oidc/callback...\n", s.GetListenAddr())
params := server.ServerParams{ params := server.ServerParams{
Verbose: config.Options.Verbose, Verbose: config.Options.Verbose,
AuthProvider: &oidc.IdentityProvider{ AuthProvider: &oidc.IdentityProvider{
@ -66,8 +52,7 @@ func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider
Register: config.Authorization.Endpoints.Register, Register: config.Authorization.Endpoints.Register,
}, },
JwtBearerParams: flows.JwtBearerFlowParams{ JwtBearerParams: flows.JwtBearerFlowParams{
Client: authzClient, Client: authzClient,
IdentityProvider: provider,
TrustedIssuer: &oauth.TrustedIssuer{ TrustedIssuer: &oauth.TrustedIssuer{
AllowAnySubject: false, AllowAnySubject: false,
Issuer: s.Addr, Issuer: s.Addr,
@ -87,7 +72,7 @@ func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider
Client: authzClient, Client: authzClient,
}, },
} }
err = s.StartLogin(button, provider, client, params) err = s.StartLogin(config.Authentication.Clients, params)
if errors.Is(err, http.ErrServerClosed) { if errors.Is(err, http.ErrServerClosed) {
fmt.Printf("\n=========================================\nServer closed.\n=========================================\n\n") fmt.Printf("\n=========================================\nServer closed.\n=========================================\n\n")
} else if err != nil { } else if err != nil {
@ -96,7 +81,7 @@ func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider
} else if config.Options.FlowType == "client_credentials" { } else if config.Options.FlowType == "client_credentials" {
params := flows.ClientCredentialsFlowParams{ params := flows.ClientCredentialsFlowParams{
Client: client, Client: nil, // # FIXME: need to do something about this being nil I think
} }
_, err := NewClientCredentialsFlowWithConfig(config, params) _, err := NewClientCredentialsFlowWithConfig(config, params)
if err != nil { if err != nil {
@ -108,13 +93,3 @@ func Login(config *Config, client *oauth.Client, provider *oidc.IdentityProvider
return nil return nil
} }
func MakeButton(url string, text string) string {
// check if we have http:// a
html := "<input type=\"button\" "
html += "class=\"button\" "
html += fmt.Sprintf("onclick=\"window.location.href='%s';\" ", url)
html += fmt.Sprintf("value=\"%s\"", text)
return html
// return "<a href=\"" + url + "\"> " + text + "</a>"
}

View file

@ -29,7 +29,7 @@ func NewClientWithConfig(config *Config) *oauth.Client {
Id: clients[0].Id, Id: clients[0].Id,
Secret: clients[0].Secret, Secret: clients[0].Secret,
Name: clients[0].Name, Name: clients[0].Name,
Issuer: clients[0].Issuer, Provider: clients[0].Provider,
Scope: clients[0].Scope, Scope: clients[0].Scope,
RedirectUris: clients[0].RedirectUris, RedirectUris: clients[0].RedirectUris,
} }
@ -53,7 +53,7 @@ func NewClientWithConfigByName(config *Config, name string) *oauth.Client {
func NewClientWithConfigByProvider(config *Config, issuer string) *oauth.Client { func NewClientWithConfigByProvider(config *Config, issuer string) *oauth.Client {
index := slices.IndexFunc(config.Authentication.Clients, func(c oauth.Client) bool { index := slices.IndexFunc(config.Authentication.Clients, func(c oauth.Client) bool {
return c.Issuer == issuer return c.Provider.Issuer == issuer
}) })
if index >= 0 { if index >= 0 {

View file

@ -16,12 +16,15 @@ func (client *Client) IsFlowInitiated() bool {
return client.FlowId != "" return client.FlowId != ""
} }
func (client *Client) BuildAuthorizationUrl(issuer string, state string) string { func (client *Client) BuildAuthorizationUrl(state string) string {
return issuer + "?" + "client_id=" + client.Id + url := client.Provider.Endpoints.Authorization + "?client_id=" + client.Id +
"&redirect_uri=" + url.QueryEscape(strings.Join(client.RedirectUris, ",")) + "&redirect_uri=" + url.QueryEscape(strings.Join(client.RedirectUris, ",")) +
"&response_type=code" + // this has to be set to "code" "&response_type=code" + // this has to be set to "code"
"&state=" + state +
"&scope=" + strings.Join(client.Scope, "+") "&scope=" + strings.Join(client.Scope, "+")
if state != "" {
url += "&state=" + state
}
return url
} }
func (client *Client) InitiateLoginFlow(loginUrl string) error { func (client *Client) InitiateLoginFlow(loginUrl string) error {
@ -90,7 +93,7 @@ func (client *Client) FetchCSRFToken(flowUrl string) error {
return fmt.Errorf("failed to extract CSRF token: not found") return fmt.Errorf("failed to extract CSRF token: not found")
} }
func (client *Client) FetchTokenFromAuthenticationServer(code string, remoteUrl string, state string) ([]byte, error) { func (client *Client) FetchTokenFromAuthenticationServer(code string, state string) ([]byte, error) {
body := url.Values{ body := url.Values{
"grant_type": {"authorization_code"}, "grant_type": {"authorization_code"},
"client_id": {client.Id}, "client_id": {client.Id},
@ -104,7 +107,7 @@ func (client *Client) FetchTokenFromAuthenticationServer(code string, remoteUrl
if state != "" { if state != "" {
body["state"] = []string{state} body["state"] = []string{state}
} }
res, err := http.PostForm(remoteUrl, body) res, err := http.PostForm(client.Provider.Endpoints.Token, body)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get ID token: %s", err) return nil, fmt.Errorf("failed to get ID token: %s", err)
} }

View file

@ -1,6 +1,7 @@
package oauth package oauth
import ( import (
"davidallendj/opaal/internal/oidc"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
@ -24,15 +25,15 @@ const (
type Client struct { type Client struct {
http.Client http.Client
Id string `db:"id" yaml:"id"` Id string `db:"id" yaml:"id"`
Secret string `db:"secret" yaml:"secret"` Secret string `db:"secret" yaml:"secret"`
Name string `db:"name" yaml:"name"` Name string `db:"name" yaml:"name"`
Description string `db:"description" yaml:"description"` Description string `db:"description" yaml:"description"`
Issuer string `db:"issuer" yaml:"issuer"` Provider oidc.IdentityProvider `db:"issuer" yaml:"provider"`
RegistrationAccessToken string `db:"registration_access_token" yaml:"registration-access-token"` RegistrationAccessToken string `db:"registration_access_token" yaml:"registration-access-token"`
RedirectUris []string `db:"redirect_uris" yaml:"redirect-uris"` RedirectUris []string `db:"redirect_uris" yaml:"redirect-uris"`
Scope []string `db:"scope" yaml:"scope"` Scope []string `db:"scope" yaml:"scope"`
Audience []string `db:"audience" yaml:"audience"` Audience []string `db:"audience" yaml:"audience"`
FlowId string FlowId string
CsrfToken string CsrfToken string
} }

View file

@ -111,26 +111,11 @@ func (p *IdentityProvider) LoadServerConfig(path string) error {
} }
func (p *IdentityProvider) FetchServerConfig() error { func (p *IdentityProvider) FetchServerConfig() error {
// make a request to a server's openid-configuration tmp, err := FetchServerConfig(p.Issuer)
req, err := http.NewRequest(http.MethodGet, p.Issuer+"/.well-known/openid-configuration", bytes.NewBuffer([]byte{}))
if err != nil { if err != nil {
return fmt.Errorf("failed to create a new request: %v", err) return err
}
client := &http.Client{} // temp client to get info and not used in flow
res, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to do request: %v", err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %v", err)
}
err = p.ParseServerConfig(body)
if err != nil {
return fmt.Errorf("failed to parse server config: %v", err)
} }
p = tmp
return nil return nil
} }
@ -147,10 +132,15 @@ func FetchServerConfig(issuer string) (*IdentityProvider, error) {
return nil, fmt.Errorf("failed to do request: %v", err) return nil, fmt.Errorf("failed to do request: %v", err)
} }
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP status code: %d", res.StatusCode)
}
body, err := io.ReadAll(res.Body) body, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err) return nil, fmt.Errorf("failed to read response body: %v", err)
} }
var p IdentityProvider var p IdentityProvider
err = p.ParseServerConfig(body) err = p.ParseServerConfig(body)
if err != nil { if err != nil {

View file

@ -58,10 +58,12 @@ func (s *Server) GetListenAddr() string {
return fmt.Sprintf("%s:%d", s.Host, s.Port) return fmt.Sprintf("%s:%d", s.Host, s.Port)
} }
func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, client *oauth.Client, params ServerParams) error { func (s *Server) StartLogin(clients []oauth.Client, params ServerParams) error {
var ( var (
target = "" target string
callback = "" callback string
client *oauth.Client
sso string
) )
// check if callback is set // check if callback is set
@ -69,6 +71,29 @@ func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, cli
callback = "/oidc/callback" callback = "/oidc/callback"
} }
// make the login page SSO buttons and authorization URLs to write to stdout
buttons := ""
fmt.Printf("Login with external identity providers: \n")
for i, client := range clients {
// fetch provider configuration before adding button
p, err := oidc.FetchServerConfig(client.Provider.Issuer)
if err != nil {
fmt.Printf("failed to fetch server config: %v\n", err)
continue
}
// if we're able to get the config, go ahead and try to fetch jwks too
if err = p.FetchJwks(); err != nil {
fmt.Printf("failed to fetch JWKS: %v\n", err)
continue
}
clients[i].Provider = *p
buttons += makeButton(fmt.Sprintf("/login?sso=%s", client.Id), client.Name)
url := client.BuildAuthorizationUrl(s.State)
fmt.Printf("\t%s\n", url)
}
var code string var code string
var accessToken string var accessToken string
r := chi.NewRouter() r := chi.NewRouter()
@ -93,21 +118,32 @@ func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, cli
// add target if query exists // add target if query exists
if r != nil { if r != nil {
target = r.URL.Query().Get("target") target = r.URL.Query().Get("target")
sso := r.URL.Query().Get("sso") sso = r.URL.Query().Get("sso")
// TODO: get client from list and build the authorization URL string
index := slices.IndexFunc(clients, func(c oauth.Client) bool {
return c.Id == sso
})
// TODO: redirect the user to authorization URL and return from func
foundClient := index >= 0
if foundClient {
client = &clients[index]
url := client.BuildAuthorizationUrl(s.State)
fmt.Printf("Redirect URL: %s\n", url)
http.Redirect(w, r, url, http.StatusFound)
return
}
} }
// show login page with notice to redirect // show login page with notice to redirect
template, err := gonja.FromFile("pages/index.html") template, err := gonja.FromFile("pages/index.html")
if err != nil { if err != nil {
panic(err) panic(err)
} }
// form, err := os.ReadFile("pages/login.html")
// if err != nil {
// fmt.Printf("failed to load login form: %v", err)
// }
data := exec.NewContext(map[string]interface{}{ data := exec.NewContext(map[string]interface{}{
// "loginForm": string(form),
"loginButtons": buttons, "loginButtons": buttons,
}) })
@ -158,7 +194,7 @@ func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, cli
// use refresh token provided to do a refresh token grant // use refresh token provided to do a refresh token grant
refreshToken := r.URL.Query().Get("refresh-token") refreshToken := r.URL.Query().Get("refresh-token")
if refreshToken != "" { if refreshToken != "" {
_, err := params.JwtBearerParams.Client.PerformRefreshTokenGrant(provider.Endpoints.Token, refreshToken) _, err := params.JwtBearerParams.Client.PerformRefreshTokenGrant(client.Provider.Endpoints.Token, refreshToken)
if err != nil { if err != nil {
fmt.Printf("failed to perform refresh token grant: %v\n", err) fmt.Printf("failed to perform refresh token grant: %v\n", err)
http.Redirect(w, r, "/error", http.StatusInternalServerError) http.Redirect(w, r, "/error", http.StatusInternalServerError)
@ -196,10 +232,15 @@ func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, cli
fmt.Printf("Authorization code: %v\n", code) fmt.Printf("Authorization code: %v\n", code)
} }
// make sure we have the correct client to use
if client == nil {
fmt.Printf("failed to find valid client")
return
}
// use code from response and exchange for bearer token (with ID token) // use code from response and exchange for bearer token (with ID token)
bearerToken, err := client.FetchTokenFromAuthenticationServer( bearerToken, err := client.FetchTokenFromAuthenticationServer(
code, code,
provider.Endpoints.Token,
s.State, s.State,
) )
if err != nil { if err != nil {
@ -229,6 +270,7 @@ func (s *Server) StartLogin(buttons string, provider *oidc.IdentityProvider, cli
// complete JWT bearer flow to receive access token from authorization server // complete JWT bearer flow to receive access token from authorization server
// fmt.Printf("bearer: %v\n", string(bearerToken)) // fmt.Printf("bearer: %v\n", string(bearerToken))
params.JwtBearerParams.IdToken = data["id_token"].(string) params.JwtBearerParams.IdToken = data["id_token"].(string)
params.JwtBearerParams.Client = client
accessToken, err = flows.NewJwtBearerFlow(params.JwtBearerEndpoints, params.JwtBearerParams) accessToken, err = flows.NewJwtBearerFlow(params.JwtBearerEndpoints, params.JwtBearerParams)
if err != nil { if err != nil {
fmt.Printf("failed to complete JWT bearer flow: %v\n", err) fmt.Printf("failed to complete JWT bearer flow: %v\n", err)
@ -407,10 +449,12 @@ func (s *Server) StartIdentityProvider() error {
// example username and password so do simplified authorization code flow // example username and password so do simplified authorization code flow
if username == "ochami" && password == "ochami" { if username == "ochami" && password == "ochami" {
client := oauth.Client{ client := oauth.Client{
Id: "ochami", Id: "ochami",
Secret: "ochami", Secret: "ochami",
Name: "ochami", Name: "ochami",
Issuer: "http://127.0.0.1:3333", Provider: oidc.IdentityProvider{
Issuer: "http://127.0.0.1:3333",
},
RedirectUris: []string{fmt.Sprintf("http://%s:%d%s", s.Host, s.Port, callback)}, RedirectUris: []string{fmt.Sprintf("http://%s:%d%s", s.Host, s.Port, callback)},
} }
@ -542,3 +586,13 @@ func (s *Server) StartIdentityProvider() error {
s.Handler = r s.Handler = r
return s.ListenAndServe() return s.ListenAndServe()
} }
func makeButton(url string, text string) string {
// check if we have http:// a
html := "<input type=\"button\" "
html += "class=\"button\" "
html += fmt.Sprintf("onclick=\"window.location.href='%s';\" ", url)
html += fmt.Sprintf("value=\"%s\">", text)
return html
// return "<a href=\"" + url + "\"> " + text + "</a>"
}