mirror of
https://github.com/davidallendj/opaal.git
synced 2025-12-20 03:27:02 -07:00
Refactored and added client credentials flow
This commit is contained in:
parent
f912890a2d
commit
f490eb4fc4
9 changed files with 113 additions and 41 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
opaal "davidallendj/opaal/internal"
|
||||
"davidallendj/opaal/internal/flows"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ var loginCmd = &cobra.Command{
|
|||
Short: "Start the login flow",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
for {
|
||||
err := opaal.Login(&config)
|
||||
err := flows.Login(&config)
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
|
|
@ -37,5 +37,6 @@ func init() {
|
|||
loginCmd.Flags().BoolVar(&config.DecodeIdToken, "decode-id-token", config.DecodeIdToken, "decode and print ID token from identity provider")
|
||||
loginCmd.Flags().BoolVar(&config.DecodeAccessToken, "decore-access-token", config.DecodeAccessToken, "decode and print access token from authorization server")
|
||||
loginCmd.Flags().BoolVar(&config.RunOnce, "once", config.RunOnce, "set whether to run login once and exit")
|
||||
loginCmd.Flags().StringVar(&config.GrantType, "grant-type", config.GrantType, "set the grant-type/authorization flow")
|
||||
rootCmd.AddCommand(loginCmd)
|
||||
}
|
||||
|
|
|
|||
24
cmd/root.go
24
cmd/root.go
|
|
@ -21,6 +21,18 @@ var rootCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to start CLI: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
rootCmd.PersistentFlags().StringVar(&configPath, "config", "", "set the config path")
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
// load config if found or create a new one
|
||||
if configPath != "" {
|
||||
|
|
@ -35,15 +47,3 @@ func initConfig() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to start CLI: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
rootCmd.PersistentFlags().StringVar(&configPath, "config", "", "set the config path")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ urls:
|
|||
jwks_uri: http://git.towk.local:3000/login/oauth/keys
|
||||
login: http://127.0.0.1:4433/self-service/login/api
|
||||
login-flow-id: http://127.0.0.1:4433/self-service/login/flows?id={id}
|
||||
register-client: http://127.0.0.1:4445/clients
|
||||
authorize-client: http://127.0.0.1:4444/oauth2/authorize
|
||||
state: ""
|
||||
response-type: code
|
||||
decode-id-token: true
|
||||
|
|
|
|||
|
|
@ -129,12 +129,17 @@ func (client *Client) FetchCSRFToken(flowUrl string) error {
|
|||
func (client *Client) FetchTokenFromAuthenticationServer(code string, remoteUrl string, state string) ([]byte, error) {
|
||||
data := url.Values{
|
||||
"grant_type": {"authorization_code"},
|
||||
"code": {code},
|
||||
"client_id": {client.Id},
|
||||
"client_secret": {client.Secret},
|
||||
"state": {state},
|
||||
"redirect_uri": {strings.Join(client.RedirectUris, ",")},
|
||||
}
|
||||
// add optional params if valid
|
||||
if code != "" {
|
||||
data["code"] = []string{code}
|
||||
}
|
||||
if state != "" {
|
||||
data["state"] = []string{state}
|
||||
}
|
||||
res, err := http.PostForm(remoteUrl, data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get ID token: %s", err)
|
||||
|
|
@ -151,9 +156,16 @@ func (client *Client) FetchTokenFromAuthorizationServer(remoteUrl string, jwt st
|
|||
// hydra endpoint: /oauth/token
|
||||
data := "grant_type=" + url.QueryEscape("urn:ietf:params:oauth:grant-type:jwt-bearer") +
|
||||
"&client_id=" + client.Id +
|
||||
"&client_secret=" + client.Secret +
|
||||
"&scope=" + strings.Join(scope, "+") +
|
||||
"&assertion=" + jwt
|
||||
"&client_secret=" + client.Secret
|
||||
|
||||
// add optional params if valid
|
||||
if jwt != "" {
|
||||
data += "&assertion=" + jwt
|
||||
}
|
||||
if scope != nil || len(scope) > 0 {
|
||||
data += "&scope=" + strings.Join(scope, "+")
|
||||
}
|
||||
|
||||
fmt.Printf("encoded params: %v\n\n", data)
|
||||
req, err := http.NewRequest("POST", remoteUrl, bytes.NewBuffer([]byte(data)))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ func NewConfig() Config {
|
|||
AccessToken: "",
|
||||
TrustedIssuers: "",
|
||||
ServerConfig: "",
|
||||
JwksUri: "",
|
||||
Login: "",
|
||||
LoginFlowId: "",
|
||||
RegisterClient: "",
|
||||
AuthorizeClient: "",
|
||||
},
|
||||
OpenBrowser: false,
|
||||
DecodeIdToken: false,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package opaal
|
||||
package flows
|
||||
|
||||
import (
|
||||
opaal "davidallendj/opaal/internal"
|
||||
"davidallendj/opaal/internal/oidc"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
|
@ -12,15 +13,7 @@ import (
|
|||
"github.com/davidallendj/go-utils/util"
|
||||
)
|
||||
|
||||
func Login(config *Config) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("config is not valid")
|
||||
}
|
||||
|
||||
// initialize client that will be used throughout login flow
|
||||
server := NewServerWithConfig(config)
|
||||
client := NewClientWithConfig(config)
|
||||
|
||||
func AuthorizationCode(config *opaal.Config, server *opaal.Server, client *opaal.Client) error {
|
||||
// initiate the login flow and get a flow ID and CSRF token
|
||||
{
|
||||
err := client.InitiateLoginFlow(config.ActionUrls.Login)
|
||||
|
|
@ -49,7 +42,7 @@ func Login(config *Config) error {
|
|||
}
|
||||
|
||||
// check if all appropriate parameters are set in config
|
||||
if !HasRequiredParams(config) {
|
||||
if !opaal.HasRequiredParams(config) {
|
||||
return fmt.Errorf("client ID must be set")
|
||||
}
|
||||
|
||||
29
internal/flows/client_credentials.go
Normal file
29
internal/flows/client_credentials.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package flows
|
||||
|
||||
import (
|
||||
opaal "davidallendj/opaal/internal"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ClientCredentials(config *opaal.Config, server *opaal.Server, client *opaal.Client) error {
|
||||
// register a new OAuth 2 client with authorization srever
|
||||
_, err := client.RegisterOAuthClient(config.ActionUrls.RegisterClient, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register OAuth client: %v", err)
|
||||
}
|
||||
|
||||
// authorize the client
|
||||
_, err = client.AuthorizeClient(config.ActionUrls.AuthorizeClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize client: %v", err)
|
||||
}
|
||||
|
||||
// request a token from the authorization server
|
||||
res, err := client.FetchTokenFromAuthorizationServer(config.ActionUrls.AccessToken, "", nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch token from authorization server: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("token: %v\n", string(res))
|
||||
return nil
|
||||
}
|
||||
28
internal/flows/login.go
Normal file
28
internal/flows/login.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package flows
|
||||
|
||||
import (
|
||||
opaal "davidallendj/opaal/internal"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Login(config *opaal.Config) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("config is not valid")
|
||||
}
|
||||
|
||||
// initialize client that will be used throughout login flow
|
||||
server := opaal.NewServerWithConfig(config)
|
||||
client := opaal.NewClientWithConfig(config)
|
||||
|
||||
fmt.Printf("grant type: %v\n", config.GrantType)
|
||||
|
||||
if config.GrantType == "authorization_code" {
|
||||
AuthorizationCode(config, server, client)
|
||||
} else if config.GrantType == "client_credentials" {
|
||||
ClientCredentials(config, server, client)
|
||||
} else {
|
||||
return fmt.Errorf("invalid grant type")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ type ActionUrls struct {
|
|||
JwksUri string `yaml:"jwks_uri"`
|
||||
Login string `yaml:"login"`
|
||||
LoginFlowId string `yaml:"login-flow-id"`
|
||||
RegisterClient string `yaml:"register-client"`
|
||||
AuthorizeClient string `yaml:"authorize-client"`
|
||||
}
|
||||
|
||||
func HasRequiredParams(config *Config) bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue