Skip to content

Commit

Permalink
Chcekpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
steve-r-west committed Nov 21, 2024
1 parent d45a748 commit 5ca97b7
Show file tree
Hide file tree
Showing 18 changed files with 821 additions and 330 deletions.
38 changes: 4 additions & 34 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/elasticpath/epcc-cli/external/headergroups"
"github.com/elasticpath/epcc-cli/external/httpclient"
"github.com/elasticpath/epcc-cli/external/json"
"github.com/elasticpath/epcc-cli/external/oidc"
"github.com/elasticpath/epcc-cli/external/resources"
"github.com/elasticpath/epcc-cli/external/rest"
log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -252,38 +253,7 @@ var loginImplicit = &cobra.Command{
},

RunE: func(cmd *cobra.Command, args []string) error {

values := url.Values{}
values.Set("grant_type", "implicit")

env := config.GetEnv()
if len(args) == 0 {
log.Debug("Arguments have been passed, not using profile EPCC_CLIENT_ID")
values.Set("client_id", env.EPCC_CLIENT_ID)
}

if len(args)%2 != 0 {
return fmt.Errorf("invalid number of arguments supplied to login command, must be multiple of 2, not %v", len(args))
}

for i := 0; i < len(args); i += 2 {
k := args[i]
values.Set(k, args[i+1])
}

token, err := authentication.GetAuthenticationToken(false, &values, true)

if err != nil {
return err
}

if token != nil {
log.Infof("Successfully authenticated with implicit token, session expires %s", time.Unix(token.Expires, 0).Format(time.RFC1123Z))
} else {
log.Warn("Did not successfully authenticate against the API")
}

return nil
return authentication.InternalImplicitAuthentication(args)
},
}

Expand Down Expand Up @@ -614,12 +584,12 @@ var loginAccountManagement = &cobra.Command{
},
}

var OidcPort uint16 = 8080
var loginOidc = &cobra.Command{
Use: "oidc",
Short: "Starts a local webserver to facilitate OIDC login flows",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {

return StartOIDCServer(8080)
return oidc.StartOIDCServer(OidcPort)
},
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ func InitializeCmd() {
LoginCmd.AddCommand(loginAccountManagement)
LoginCmd.AddCommand(loginOidc)

loginOidc.PersistentFlags().Uint16VarP(&OidcPort, "port", "p", 8080, "The port to listen on for the OIDC callback")
logoutCmd.AddCommand(logoutBearer)
logoutCmd.AddCommand(logoutCustomer)
logoutCmd.AddCommand(logoutAccountManagement)
Expand Down
43 changes: 43 additions & 0 deletions external/authentication/internal_login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package authentication

import (
"fmt"
"github.com/elasticpath/epcc-cli/config"
log "github.com/sirupsen/logrus"
"net/url"
"time"
)

func InternalImplicitAuthentication(args []string) error {
values := url.Values{}
values.Set("grant_type", "implicit")

env := config.GetEnv()
if len(args) == 0 {
log.Debug("Arguments have been passed, not using profile EPCC_CLIENT_ID")
values.Set("client_id", env.EPCC_CLIENT_ID)
}

if len(args)%2 != 0 {
return fmt.Errorf("invalid number of arguments supplied to login command, must be multiple of 2, not %v", len(args))
}

for i := 0; i < len(args); i += 2 {
k := args[i]
values.Set(k, args[i+1])
}

token, err := GetAuthenticationToken(false, &values, true)

if err != nil {
return err
}

if token != nil {
log.Infof("Successfully authenticated with implicit token, session expires %s", time.Unix(token.Expires, 0).Format(time.RFC1123Z))
} else {
log.Warn("Did not successfully authenticate against the API")
}

return nil
}
96 changes: 96 additions & 0 deletions external/oidc/callback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package oidc

import (
"context"
"encoding/base64"
gojson "encoding/json"
"fmt"
"github.com/elasticpath/epcc-cli/external/authentication"
"github.com/elasticpath/epcc-cli/external/httpclient"
"github.com/elasticpath/epcc-cli/external/rest"
"net/http"
)

type CallbackPageInfo struct {
LoginType string
ErrorTitle string
ErrorDescription string
AccountTokenResponse *authentication.AccountManagementAuthenticationTokenResponse
AccountTokenStructBase64 []string
}

func GetCallbackData(ctx context.Context, port uint16, r *http.Request) (*CallbackPageInfo, error) {
// Parse the query parameters
queryParams := r.URL.Query()

// Convert query parameters to a map
data := make(map[string]string)
for key, values := range queryParams {
data[key] = values[0] // Use the first value if multiple are provided
}

data["uri"] = fmt.Sprintf("http://localhost:", port)

if data["code"] != "" {

state, err := r.Cookie("state")

if err != nil {
return nil, fmt.Errorf("could not get state cookie: %w", err)
}

verifier, err := r.Cookie("code_verifier")

if err != nil {
return nil, fmt.Errorf("could not get verifier cookie: %w", err)
}

result, err := rest.CreateInternal(context.Background(), &httpclient.HttpParameterOverrides{}, []string{"account-management-authentication-token",
"authentication_mechanism", "oidc",
"oauth_authorization_code", data["code"],
"oauth_redirect_uri", fmt.Sprintf("http://localhost:%d/callback", port),
"oauth_state", state.Value,
"oauth_code_verifier", verifier.Value,
}, false, "", true)

if err != nil {
return nil, fmt.Errorf("could not get account tokens: %w", err)
}

cpi := CallbackPageInfo{
LoginType: "AM",
}

err = gojson.Unmarshal([]byte(result), &cpi.AccountTokenResponse)

if err != nil {
return nil, fmt.Errorf("could not unmarshal response: %w", err)
}

for _, v := range cpi.AccountTokenResponse.Data {

str, err := gojson.Marshal(v)

if err != nil {
return nil, fmt.Errorf("could not encode token: %w", err)
}

base64.URLEncoding.EncodeToString(str)

cpi.AccountTokenStructBase64 = append(cpi.AccountTokenStructBase64, base64.URLEncoding.EncodeToString(str))
}

return &cpi, nil
} else if data["error"] == "" {

return &CallbackPageInfo{
ErrorTitle: "Bad Response",
ErrorDescription: "Invalid response from IdP, no code or error query parameter",
}, nil
} else {
return &CallbackPageInfo{
ErrorTitle: data["error"],
ErrorDescription: data["error_description"],
}, nil
}
}
74 changes: 74 additions & 0 deletions external/oidc/get_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package oidc

import (
"context"
"encoding/base64"
gojson "encoding/json"
"fmt"
"github.com/elasticpath/epcc-cli/external/authentication"
log "github.com/sirupsen/logrus"
"net/http"
"os"
"time"
)

type TokenPageInfo struct {
LoginType string
ErrorTitle string
ErrorDescription string
Name string
Id string
}

func GetTokenData(ctx context.Context, port uint16, r *http.Request) (*TokenPageInfo, error) {
// Parse the query parameters
queryParams := r.URL.Query()

// Convert query parameters to a map
data := make(map[string]string)
for key, values := range queryParams {
data[key] = values[0] // Use the first value if multiple are provided
}

if data["login_type"] == "AM" {
token := data["token"]
amTokenJson, err := base64.URLEncoding.DecodeString(token)

if err != nil {
return nil, fmt.Errorf("could not get decode am token: %w", err)
}

amToken := authentication.AccountManagementAuthenticationTokenStruct{}

err = gojson.Unmarshal(amTokenJson, &amToken)

if err != nil {
return nil, fmt.Errorf("could not get unmarshal am token: %w", err)
}

authentication.SaveAccountManagementAuthenticationToken(amToken)

apiToken := authentication.GetApiToken()

if apiToken != nil {
if apiToken.Identifier == "client_credentials" {
log.Warnf("You are currently logged in with client_credentials, please switch to implicit with `epcc login implicit` to use the account management token correctly. Mixing client_credentials and the account management token can lead to unintended results.")
}
}

go func() {
time.Sleep(2 * time.Second)
log.Infof("Authentication complete, shutting down")
os.Exit(0)
}()

return &TokenPageInfo{
LoginType: "AM",
Name: amToken.AccountName,
Id: amToken.AccountId,
}, nil

}

return nil, fmt.Errorf("invalid login type")
}
Loading

0 comments on commit 5ca97b7

Please sign in to comment.