Skip to content

Commit

Permalink
implement own error type that supports help message
Browse files Browse the repository at this point in the history
  • Loading branch information
zachmann committed Aug 6, 2021
1 parent 1f01289 commit 9ba3ab4
Showing 1 changed file with 62 additions and 15 deletions.
77 changes: 62 additions & 15 deletions liboidcagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@ import (
"time"
)

// OIDCAgentError is an error type used for returning errors
type OIDCAgentError struct {
err string
help string
remote bool
}

func (e *OIDCAgentError) Error() string {
rem := ""
if e.remote {
rem = "(remote) "
}
return fmt.Sprintf("oidc-agent %serror: %s", rem, e.err)
}

// Help returns a help message if available. This help message helps the user to
// solve the problem. If a help message is available it SHOULD be displayed to
// the user. One can use ErrorWithHelp to obtain both.
func (e *OIDCAgentError) Help() string {
return e.help
}

// ErrorWithHelp returns a string combining the error message and the help
// message (if available).
func (e *OIDCAgentError) ErrorWithHelp() string {
help := e.Help()
err := e.Error()
if help != "" {
return fmt.Sprintf("%s\n%s", err, help)
}
return err
}

func oidcAgentErrorWrap(err error) error {
if err == nil {
return nil
}
return &OIDCAgentError{
err: err.Error(),
}
}

// TokenResponse is a parsed response from the oidc-agent
type TokenResponse struct {
// The access token
Expand All @@ -32,8 +74,8 @@ type TokenRequest struct {
Scopes []string
// The audiences for the requested access token
Audiences []string
// An string describing the requesting application (i.e. its name). It might
// be displayed to the user, if the requested must be confirmed or an account
// A string describing the requesting application (i.e. its name). It might
// be displayed to the user, if the request must be confirmed or an account
// configuration loaded.
ApplicationHint string
}
Expand All @@ -45,6 +87,7 @@ type tokenResponse struct {

Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
Help string `json:"info,omitempty"`
}

type tokenRequest struct {
Expand Down Expand Up @@ -72,21 +115,24 @@ func createTokenRequest(req TokenRequest) (string, error) {
}

func parseIpcResponse(remote bool, response []byte) (res TokenResponse, err error) {
rem := ""
if remote {
rem = "remote "
}
var rawResponse tokenResponse
if err = json.Unmarshal(response, &rawResponse); err != nil {
err = fmt.Errorf("unable to unmarshal: %s", response)
err = oidcAgentErrorWrap(fmt.Errorf("unable to unmarshal: %s", response))
return
}
if rawResponse.Error != "" {
err = fmt.Errorf("%sagent error: %s", rem, rawResponse.Error)
err = &OIDCAgentError{
err: rawResponse.Error,
help: rawResponse.Help,
remote: remote,
}
return
}
if rawResponse.Status == "failure" {
err = fmt.Errorf("%sstatus is \"failure\"", rem)
err = &OIDCAgentError{
err: "unknown error",
remote: remote,
}
return
}
res = TokenResponse{
Expand All @@ -100,34 +146,35 @@ func parseIpcResponse(remote bool, response []byte) (res TokenResponse, err erro
// GetTokenResponse gets a token response
func GetTokenResponse(req TokenRequest) (resp TokenResponse, err error) {
if req.ShortName == "" && req.IssuerURL == "" {
err = fmt.Errorf("'Shortname' and 'IssuerURL' both not provided")
err = &OIDCAgentError{err: "'Shortname' and 'IssuerURL' both not provided"}
return
}
ipcReq, err := createTokenRequest(req)
if err != nil {
err = fmt.Errorf("cannot create agent request: %s", err)
err = oidcAgentErrorWrap(fmt.Errorf("cannot create agent request: %s", err))
return
}
ipcResponse, err := communicateEncrypted(false, ipcReq)
if err != nil {
if err.Error() != "$OIDC_SOCK not set" {
err = oidcAgentErrorWrap(err)
if strings.Contains(err.Error(), "$OIDC_SOCK not set") {
return
}
ipcResponse, err = communicateEncrypted(true, ipcReq)
if err != nil {
err = fmt.Errorf("$OIDC_SOCK not set and %s on remote", err)
err = oidcAgentErrorWrap(fmt.Errorf("$OIDC_SOCK not set and %s on remote", err))
return
}
resp, err = parseIpcResponse(true, []byte(ipcResponse))
return
}
resp, err = parseIpcResponse(false, []byte(ipcResponse))
if err != nil && err.Error() == "Agent error: No account configured with that short name" {
if err != nil && strings.Contains(err.Error(), "No account configured with that short name") {
localErr := err
// Try remote
ipcResponse, err = communicateEncrypted(true, ipcReq)
if err != nil {
if err.Error() == "$OIDC_REMOTE_SOCK not set" {
if strings.Contains(err.Error(), "$OIDC_REMOTE_SOCK not set") {
err = localErr
}
return
Expand Down

0 comments on commit 9ba3ab4

Please sign in to comment.