diff --git a/internal/flows/jwt_bearer.go b/internal/flows/jwt_bearer.go
index a0287d9..2e93265 100644
--- a/internal/flows/jwt_bearer.go
+++ b/internal/flows/jwt_bearer.go
@@ -51,9 +51,6 @@ func NewJwtBearerFlow(eps JwtBearerFlowEndpoints, params JwtBearerFlowParams) (s
if client == nil {
return "", fmt.Errorf("invalid client (client is nil)")
}
- if verbose {
- fmt.Printf("ID token (IDP): %s\n access token (IDP): %s", accessToken, idToken)
- }
if accessToken != "" {
_, err := jws.Verify([]byte(accessToken), jws.WithKeySet(client.Provider.KeySet), jws.WithValidateKey(true))
if err != nil {
diff --git a/internal/new.go b/internal/new.go
index 2799d88..7e3e35c 100644
--- a/internal/new.go
+++ b/internal/new.go
@@ -94,7 +94,6 @@ func NewServerWithConfig(conf *Config) *server.Server {
Host: conf.Server.Issuer.Host,
Port: conf.Server.Issuer.Port,
Endpoints: conf.Server.Issuer.Endpoints,
- Clients: conf.Server.Issuer.Clients,
},
}
return server
diff --git a/internal/oauth/authenticate.go b/internal/oauth/authenticate.go
index 4af65cb..b579e8e 100644
--- a/internal/oauth/authenticate.go
+++ b/internal/oauth/authenticate.go
@@ -109,14 +109,12 @@ func (client *Client) FetchTokenFromAuthenticationServer(code string, state stri
}
res, err := http.PostForm(client.Provider.Endpoints.Token, body)
if err != nil {
- return nil, fmt.Errorf("failed to get ID token: %v", err)
+ return nil, fmt.Errorf("failed to get ID token: %s", err)
}
- b, err := io.ReadAll(res.Body)
- if err != nil {
- return nil, fmt.Errorf("failed to read response body: %v", err)
- }
- fmt.Printf("%s\n", string(b))
defer res.Body.Close()
- return b, nil
+ // domain, _ := url.Parse("http://127.0.0.1")
+ // client.Jar.SetCookies(domain, res.Cookies())
+
+ return io.ReadAll(res.Body)
}
diff --git a/internal/oidc/oidc.go b/internal/oidc/oidc.go
index f52e0c4..206f68f 100644
--- a/internal/oidc/oidc.go
+++ b/internal/oidc/oidc.go
@@ -175,6 +175,7 @@ func UpdateEndpoints(eps *Endpoints, other *Endpoints) {
if ep != nil {
if *ep == "" {
*ep = s
+ fmt.Printf("updated %s\n", s)
}
}
}
diff --git a/internal/server/idp.go b/internal/server/idp.go
index bb82a28..35b4051 100644
--- a/internal/server/idp.go
+++ b/internal/server/idp.go
@@ -3,6 +3,7 @@ package server
import (
"crypto/rand"
"crypto/rsa"
+ "davidallendj/opaal/internal/oauth"
"davidallendj/opaal/internal/oidc"
"encoding/json"
"fmt"
@@ -21,22 +22,6 @@ import (
"github.com/lestrrat-go/jwx/v2/jwt"
)
-// TODO: make this a completely separate server
-type IdentityProviderServer struct {
- Host string `yaml:"host"`
- Port int `yaml:"port"`
- Endpoints oidc.Endpoints `yaml:"endpoints"`
- Clients []RegisteredClient `yaml:"clients"`
-}
-
-// NOTE: could we use a oauth.Client here instead??
-type RegisteredClient struct {
- Id string `yaml:"id"`
- Secret string `yaml:"secret"`
- Name string `yaml:"name"`
- RedirectUris []string `yaml:"redirect-uris"`
-}
-
func (s *Server) StartIdentityProvider() error {
// NOTE: this example does NOT implement CSRF tokens nor use them
@@ -44,13 +29,19 @@ func (s *Server) StartIdentityProvider() error {
var (
r = chi.NewRouter()
// clients = []oauth.Client{}
+ callback = ""
activeCodes = []string{}
)
+ // check if callback is set
+ if s.Callback == "" {
+ callback = "/oidc/callback"
+ }
+
// update endpoints that have values set
defaultEps := oidc.Endpoints{
- Authorization: "http://" + s.Addr + "/oauth2/authorize",
- Token: "http://" + s.Addr + "/oauth2/token",
+ Authorization: "http://" + s.Addr + "/oauth/authorize",
+ Token: "http://" + s.Addr + "/oauth/token",
JwksUri: "http://" + s.Addr + "/.well-known/jwks.json",
}
oidc.UpdateEndpoints(&s.Issuer.Endpoints, &defaultEps)
@@ -147,18 +138,21 @@ func (s *Server) StartIdentityProvider() error {
username := r.Form.Get("username")
password := r.Form.Get("password")
- if len(s.Issuer.Clients) <= 0 {
- fmt.Printf("no registered clients found with identity provider (add them in config)\n")
- return
- }
-
// example username and password so do simplified authorization code flow
- if username == "openchami" && password == "openchami" {
- client := s.Issuer.Clients[0]
+ if username == "ochami" && password == "ochami" {
+ client := oauth.Client{
+ Id: "ochami",
+ Secret: "ochami",
+ Name: "ochami",
+ Provider: oidc.IdentityProvider{
+ Issuer: "http://127.0.0.1:3333",
+ },
+ RedirectUris: []string{fmt.Sprintf("http://%s:%d%s", s.Host, s.Port, callback)},
+ }
// check if there are any redirect URIs supplied
if len(client.RedirectUris) <= 0 {
- fmt.Printf("no redirect URIs found for client %s (ID: %s)\n", client.Name, client.Id)
+ fmt.Printf("no redirect URIs found")
return
}
for _, url := range client.RedirectUris {
@@ -266,13 +260,9 @@ func (s *Server) StartIdentityProvider() error {
return
}
- // find a valid client
- index := slices.IndexFunc(s.Issuer.Clients, func(c RegisteredClient) bool {
- fmt.Printf("%s ? %s\n", c.Id, clientId)
- return c.Id == clientId
- })
- if index < 0 {
- fmt.Printf("no valid client found")
+ // check that we're using the default registered client
+ if clientId != "ochami" {
+ fmt.Printf("invalid client\n")
return
}
diff --git a/internal/server/server.go b/internal/server/server.go
index 3fdae97..c829a34 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -25,6 +25,12 @@ type Server struct {
Issuer IdentityProviderServer `yaml:"issuer"`
}
+type IdentityProviderServer struct {
+ Host string `yaml:"host"`
+ Port int `yaml:"port"`
+ Endpoints oidc.Endpoints `yaml:"endpoints"`
+}
+
type ServerParams struct {
AuthProvider *oidc.IdentityProvider
Verbose bool
@@ -57,7 +63,7 @@ func (s *Server) StartLogin(clients []oauth.Client, params ServerParams) error {
// make the login page SSO buttons and authorization URLs to write to stdout
buttons := ""
- fmt.Printf("Login with an identity provider: \n")
+ 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)
@@ -74,7 +80,8 @@ func (s *Server) StartLogin(clients []oauth.Client, params ServerParams) error {
clients[i].Provider = *p
buttons += makeButton(fmt.Sprintf("/login?sso=%s", client.Id), client.Name)
- fmt.Printf("\t%s: /login?sso=%s\n", client.Name, client.Id)
+ url := client.BuildAuthorizationUrl(s.State)
+ fmt.Printf("\t%s\n", url)
}
var code string
@@ -114,9 +121,7 @@ func (s *Server) StartLogin(clients []oauth.Client, params ServerParams) error {
client = &clients[index]
url := client.BuildAuthorizationUrl(s.State)
- if params.Verbose {
- fmt.Printf("Redirect URL: %s\n", url)
- }
+ fmt.Printf("Redirect URL: %s\n", url)
http.Redirect(w, r, url, http.StatusFound)
return
}
@@ -141,47 +146,38 @@ func (s *Server) StartLogin(clients []oauth.Client, params ServerParams) error {
p = params.AuthProvider
jwks []byte
)
-
- fetchAndMarshal := func() (err error) {
- err = p.FetchJwks()
+ // try and get the JWKS from param first
+ if p.Endpoints.JwksUri != "" {
+ err := p.FetchJwks()
if err != nil {
- fmt.Printf("failed to fetch keys: %v\n", err)
- return
+ fmt.Printf("failed to fetch keys using JWKS url...trying to fetch config and try again...\n")
}
jwks, err = json.Marshal(p.KeySet)
if err != nil {
fmt.Printf("failed to marshal JWKS: %v\n", err)
}
- return
- }
-
- // try and get the JWKS from param first
- if p.Endpoints.JwksUri != "" {
- if err := fetchAndMarshal(); err != nil {
- w.Write(jwks)
- return
- }
- }
-
- // otherwise or if fetching the JWKS failed, try and fetch the whole config first and try again
- if p.Endpoints.Config != "" {
- if err := p.FetchServerConfig(); err != nil {
+ } else if p.Endpoints.Config != "" && jwks == nil {
+ // otherwise, try and fetch the whole config and try again
+ err := p.FetchServerConfig()
+ if err != nil {
fmt.Printf("failed to fetch server config: %v\n", err)
- http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ http.Redirect(w, r, "/error", http.StatusInternalServerError)
+ return
+ }
+ err = p.FetchJwks()
+ if err != nil {
+ fmt.Printf("failed to fetch JWKS after fetching server config: %v\n", err)
+ http.Redirect(w, r, "/error", http.StatusInternalServerError)
return
}
- } else {
- fmt.Printf("getting JWKS from param failed and endpoints config unavailable\n")
- http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
- return
}
- if err := fetchAndMarshal(); err != nil {
- fmt.Printf("failed to fetch and marshal JWKS after config update: %v\n", err)
- http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ // forward the JWKS from the authorization server
+ if jwks == nil {
+ fmt.Printf("no JWKS was fetched from authorization server\n")
+ http.Redirect(w, r, "/error", http.StatusInternalServerError)
return
}
-
w.Write(jwks)
})
r.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
diff --git a/pages/login.html b/pages/login.html
index c25f8c3..e55f5cf 100644
--- a/pages/login.html
+++ b/pages/login.html
@@ -7,7 +7,7 @@
Forgot Username?
-
+