Skip to content

Commit

Permalink
Merge pull request #54 from DenitsaTH/ztat-1014-handle-codeless-error
Browse files Browse the repository at this point in the history
Handle StatResult.Code is empty string
  • Loading branch information
AaronAtDuo authored Jan 28, 2025
2 parents cb17708 + 2d1f351 commit 8aff7fd
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
8 changes: 8 additions & 0 deletions authapi/authapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (api *AuthApi) Ping() (*PingResult, error) {
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand All @@ -72,6 +73,7 @@ func (api *AuthApi) Check() (*CheckResult, error) {
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand All @@ -98,6 +100,7 @@ func (api *AuthApi) Logo() (*LogoResult, error) {
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand Down Expand Up @@ -145,6 +148,7 @@ func (api *AuthApi) Enroll(options ...func(*url.Values)) (*EnrollResult, error)
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand Down Expand Up @@ -174,6 +178,7 @@ func (api *AuthApi) EnrollStatus(userid string,
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand Down Expand Up @@ -239,6 +244,7 @@ func (api *AuthApi) Preauth(options ...func(*url.Values)) (*PreauthResult, error
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand Down Expand Up @@ -348,6 +354,7 @@ func (api *AuthApi) Auth(factor string, options ...func(*url.Values)) (*AuthResu
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}

Expand Down Expand Up @@ -377,5 +384,6 @@ func (api *AuthApi) AuthStatus(txid string) (*AuthStatusResult, error) {
if err = json.Unmarshal(body, ret); err != nil {
return nil, err
}
ret.SyncCode()
return ret, nil
}
41 changes: 39 additions & 2 deletions authapi/authapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"testing"
"time"

"github.com/duosecurity/duo_api_golang"
duoapi "github.com/duosecurity/duo_api_golang"
)

func buildAuthApi(url string, proxy func(*http.Request) (*url.URL, error)) *AuthApi {
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestLogo(t *testing.T) {
}
}

// Test a failure logo reqeust / response.
// Test a failure logo request / response.
func TestLogoError(t *testing.T) {
ts := httptest.NewTLSServer(
http.HandlerFunc(
Expand Down Expand Up @@ -602,3 +602,40 @@ func TestAuthStatus(t *testing.T) {
t.Error("Unexpected response status msg: " + res.Response.Status_Msg)
}
}

// Test a response with empty code.
func TestEmptyResponseCode(t *testing.T) {
ts := httptest.NewTLSServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
// Return a 400, as if the logo was not found.
w.WriteHeader(400)
fmt.Fprintln(w, `
{
"stat": "FAIL",
"code": "",
"message": "Code is empty",
"message_detail": "Deal with it"
}`)
}))
defer ts.Close()

duo := buildAuthApi(ts.URL, nil)

res, err := duo.Logo()
if err != nil {
t.Error("Failed TestCheck: " + err.Error())
}
if res.Stat != "FAIL" {
t.Error("Expected FAIL, but got " + res.Stat)
}
if res.Code == nil || *res.Code != 0 {
t.Error("Unexpected response code.")
}
if res.Message == nil || *res.Message != "Code is empty" {
t.Error("Unexpected message.")
}
if res.Message_Detail == nil || *res.Message_Detail != "Deal with it" {
t.Error("Unexpected message detail.")
}
}
35 changes: 31 additions & 4 deletions duoapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,41 @@ func (duoapi *DuoApi) buildOptions(options ...DuoApiOption) *requestOptions {
return opts
}

type NullableInt32 struct {
value *int32
}

// API calls will return a StatResult object. On success, Stat is 'OK'.
// On error, Stat is 'FAIL', and Code, Message, and Message_Detail
// contain error information.
type StatResult struct {
Stat string
Code *int32
Message *string
Message_Detail *string
Stat string `json:"stat"`
Ncode NullableInt32 `json:"code"`
Code *int32 `json:"-"`
Message *string `json:"message"`
Message_Detail *string `json:"message_detail"`
}

func (n *NullableInt32) UnmarshalJSON(data []byte) error {
var raw interface{}

if err := json.Unmarshal(data, &raw); err != nil {
return err
}

switch v := raw.(type) {
case float64:
intVal := int32(v)
n.value = &intVal
case string:
intVal := int32(0)
n.value = &intVal
}
return nil
}

func (s *StatResult) SyncCode() {
s.Code = s.Ncode.value
}

// SetCustomHTTPClient allows one to set a completely custom http client that
Expand Down

0 comments on commit 8aff7fd

Please sign in to comment.