From c0449d8d9045cd805d7dedceb2596cda097562c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 05:30:58 +0000 Subject: [PATCH 01/54] Bump github.com/google/uuid from 1.2.0 to 1.3.0 Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.2.0 to 1.3.0. - [Release notes](https://github.com/google/uuid/releases) - [Commits](https://github.com/google/uuid/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: github.com/google/uuid dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 5 ++--- go.sum | 11 ++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index ce3e397e5..f210e9fba 100644 --- a/go.mod +++ b/go.mod @@ -16,16 +16,15 @@ require ( github.com/danieljoos/wincred v1.1.0 github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/godbus/dbus v4.1.0+incompatible // indirect - github.com/google/uuid v1.2.0 + github.com/google/uuid v1.3.0 github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d github.com/kr/text v0.2.0 // indirect - github.com/magefile/mage v1.11.0 // indirect github.com/marshallbrekka/go-u2fhost v0.0.0-20210111072507-3ccdec8c8105 github.com/mattn/go-colorable v0.1.8 // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/mxschmitt/playwright-go v0.1100.0 github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.7.1 + github.com/sirupsen/logrus v1.8.1 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/smartystreets/assertions v1.0.0 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect diff --git a/go.sum b/go.sum index 0cffc246b..28e05cb80 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -112,9 +112,6 @@ github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= -github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/marshallbrekka/go-u2fhost v0.0.0-20210111072507-3ccdec8c8105 h1:Si3VAYdC1ZtA58UsDXxlkbpF5EMWxoCJP9gn1cYQ+vc= github.com/marshallbrekka/go-u2fhost v0.0.0-20210111072507-3ccdec8c8105/go.mod h1:VyqGj5jbZtzHO11cS7rkDh/owr/rNCEM98IhQwWvmXg= @@ -158,8 +155,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg= -github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= From 531a2551fda4f91c75f11f1771d84d976c603a7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 05:31:28 +0000 Subject: [PATCH 02/54] Bump github.com/beevik/etree from 1.0.1 to 1.1.0 Bumps [github.com/beevik/etree](https://github.com/beevik/etree) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/beevik/etree/releases) - [Changelog](https://github.com/beevik/etree/blob/master/RELEASE_NOTES.md) - [Commits](https://github.com/beevik/etree/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: github.com/beevik/etree dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fde88b987..311b87b7e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/avast/retry-go v2.6.0+incompatible github.com/aws/aws-sdk-go v1.40.9 - github.com/beevik/etree v1.0.1 + github.com/beevik/etree v1.1.0 github.com/danieljoos/wincred v1.1.0 github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/godbus/dbus v4.1.0+incompatible // indirect diff --git a/go.sum b/go.sum index 757a69e8e..7a920d445 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/aws/aws-sdk-go v1.40.9 h1:pMq7LecsVESBgCfYrJFy/MELrOXbM0QmCr5I3wh6tLQ github.com/aws/aws-sdk-go v1.40.9/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/bearsh/hid v1.3.0 h1:GLNa8hvEzJxzQEEpheDUr2SivvH7iwTrJrDhFKutfX8= github.com/bearsh/hid v1.3.0/go.mod h1:KbQByg8WfPr92v7aaKAHTtZUEVG7e2XRpcF8+TopQv8= -github.com/beevik/etree v1.0.1 h1:lWzdj5v/Pj1X360EV7bUudox5SRipy4qZLjY0rhb0ck= -github.com/beevik/etree v1.0.1/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= From 2be5a3b1d09b2437dd5708404c21a8352b93dd73 Mon Sep 17 00:00:00 2001 From: Christian Meyer Date: Wed, 23 Mar 2022 23:41:16 +0100 Subject: [PATCH 03/54] refactored AzureAD authentication for AWS IAM federation --- pkg/provider/aad/aad.go | 1470 +++++++++++++++++---------------------- 1 file changed, 638 insertions(+), 832 deletions(-) diff --git a/pkg/provider/aad/aad.go b/pkg/provider/aad/aad.go index 0c2607097..6f738d290 100644 --- a/pkg/provider/aad/aad.go +++ b/pkg/provider/aad/aad.go @@ -19,7 +19,6 @@ import ( "github.com/versent/saml2aws/v2/pkg/creds" "github.com/versent/saml2aws/v2/pkg/prompter" "github.com/versent/saml2aws/v2/pkg/provider" - "golang.org/x/net/html" ) // Client wrapper around AzureAD enabling authentication and retrieval of assertions @@ -30,11 +29,13 @@ type Client struct { idpAccount *cfg.IDPAccount } -// Autogenerate startSAML Response struct -// some case, some fields is not exists -type startSAMLResponse struct { +// Autogenerated ConvergedSignIn Response struct +// for some cases, some fields may not exist +type ConvergedSignInResponse struct { FShowPersistentCookiesWarning bool `json:"fShowPersistentCookiesWarning"` + URLMsaSignUp string `json:"urlMsaSignUp"` URLMsaLogout string `json:"urlMsaLogout"` + URLOtherIdpForget string `json:"urlOtherIdpForget"` ShowCantAccessAccountLink bool `json:"showCantAccessAccountLink"` URLGitHubFed string `json:"urlGitHubFed"` FShowSignInWithGitHubOnlyOnCredPicker bool `json:"fShowSignInWithGitHubOnlyOnCredPicker"` @@ -42,10 +43,10 @@ type startSAMLResponse struct { IShowResendCodeDelay int `json:"iShowResendCodeDelay"` SSMSCtryPhoneData string `json:"sSMSCtryPhoneData"` FUseInlinePhoneNumber bool `json:"fUseInlinePhoneNumber"` + FDetectBrowserCapabilities bool `json:"fDetectBrowserCapabilities"` URLSessionState string `json:"urlSessionState"` URLResetPassword string `json:"urlResetPassword"` URLMsaResetPassword string `json:"urlMsaResetPassword"` - URLLogin string `json:"urlLogin"` URLSignUp string `json:"urlSignUp"` URLGetCredentialType string `json:"urlGetCredentialType"` URLGetOneTimeCode string `json:"urlGetOneTimeCode"` @@ -53,11 +54,6 @@ type startSAMLResponse struct { URLForget string `json:"urlForget"` URLDisambigRename string `json:"urlDisambigRename"` URLGoToAADError string `json:"urlGoToAADError"` - URLDssoStatus string `json:"urlDssoStatus"` - URLFidoHelp string `json:"urlFidoHelp"` - URLFidoLogin string `json:"urlFidoLogin"` - URLPostAad string `json:"urlPostAad"` - URLPostMsa string `json:"urlPostMsa"` URLPIAEndAuth string `json:"urlPIAEndAuth"` FCBShowSignUp bool `json:"fCBShowSignUp"` FKMSIEnabled bool `json:"fKMSIEnabled"` @@ -82,388 +78,162 @@ type startSAMLResponse struct { ErrorSubcode string `json:"error_subcode"` State string `json:"state"` } `json:"oCancelPostParams"` - IAllowedIdentities int `json:"iAllowedIdentities"` - IRemoteNgcPollingType int `json:"iRemoteNgcPollingType"` - IsGlobalTenant bool `json:"isGlobalTenant"` - FIsFidoSupported bool `json:"fIsFidoSupported"` - FUseNewNoPasswordTypes bool `json:"fUseNewNoPasswordTypes"` - IMaxStackForKnockoutAsyncComponents int `json:"iMaxStackForKnockoutAsyncComponents"` - StrCopyrightTxt string `json:"strCopyrightTxt"` - FShowButtons bool `json:"fShowButtons"` - URLCdn string `json:"urlCdn"` - URLFooterTOU string `json:"urlFooterTOU"` - URLFooterPrivacy string `json:"urlFooterPrivacy"` - URLPost string `json:"urlPost"` - URLRefresh string `json:"urlRefresh"` - URLCancel string `json:"urlCancel"` - IPawnIcon int `json:"iPawnIcon"` - IPollingInterval int `json:"iPollingInterval"` - SPOSTUsername string `json:"sPOST_Username"` - SFT string `json:"sFT"` - SFTName string `json:"sFTName"` - SSessionIdentifierName string `json:"sSessionIdentifierName"` - SCtx string `json:"sCtx"` - IProductIcon int `json:"iProductIcon"` - URLReportPageLoad string `json:"urlReportPageLoad"` - StaticTenantBranding interface{} `json:"staticTenantBranding"` - OAppCobranding struct { - } `json:"oAppCobranding"` - IBackgroundImage int `json:"iBackgroundImage"` - ArrSessions []interface{} `json:"arrSessions"` - FUseConstantPolling bool `json:"fUseConstantPolling"` - FUseFlowTokenAsCanary bool `json:"fUseFlowTokenAsCanary"` - FApplicationInsightsEnabled bool `json:"fApplicationInsightsEnabled"` - IApplicationInsightsEnabledPercentage int `json:"iApplicationInsightsEnabledPercentage"` - URLSetDebugMode string `json:"urlSetDebugMode"` - FEnableCSSAnimation bool `json:"fEnableCssAnimation"` - FAllowGrayOutLightBox bool `json:"fAllowGrayOutLightBox"` - FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` - Scid int `json:"scid"` - Hpgact int `json:"hpgact"` - Hpgid int `json:"hpgid"` - Pgid string `json:"pgid"` - APICanary string `json:"apiCanary"` - Canary string `json:"canary"` - CorrelationID string `json:"correlationId"` - SessionID string `json:"sessionId"` - Locale struct { - Mkt string `json:"mkt"` - Lcid int `json:"lcid"` - } `json:"locale"` - SlMaxRetry int `json:"slMaxRetry"` - SlReportFailure bool `json:"slReportFailure"` - Strings struct { - Desktopsso struct { - Authenticatingmessage string `json:"authenticatingmessage"` - } `json:"desktopsso"` - } `json:"strings"` - Enums struct { - ClientMetricsModes struct { - None int `json:"None"` - SubmitOnPost int `json:"SubmitOnPost"` - SubmitOnRedirect int `json:"SubmitOnRedirect"` - InstrumentPlt int `json:"InstrumentPlt"` - } `json:"ClientMetricsModes"` - } `json:"enums"` - Urls struct { - Instr struct { - Pageload string `json:"pageload"` - Dssostatus string `json:"dssostatus"` - } `json:"instr"` - } `json:"urls"` - Browser struct { - Ltr int `json:"ltr"` - Other int `json:"_Other"` - Full int `json:"Full"` - REOther int `json:"RE_Other"` - B struct { - Name string `json:"name"` - Major int `json:"major"` - Minor int `json:"minor"` - } `json:"b"` - Os struct { - Name string `json:"name"` - Version string `json:"version"` - } `json:"os"` - V int `json:"V"` - } `json:"browser"` - Watson struct { - URL string `json:"url"` - Bundle string `json:"bundle"` - Sbundle string `json:"sbundle"` - Fbundle string `json:"fbundle"` - ResetErrorPeriod int `json:"resetErrorPeriod"` - MaxCorsErrors int `json:"maxCorsErrors"` - MaxInjectErrors int `json:"maxInjectErrors"` - MaxErrors int `json:"maxErrors"` - MaxTotalErrors int `json:"maxTotalErrors"` - ExpSrcs []string `json:"expSrcs"` - EnvErrorRedirect bool `json:"envErrorRedirect"` - EnvErrorURL string `json:"envErrorUrl"` - } `json:"watson"` - Loader struct { - CdnRoots []string `json:"cdnRoots"` - } `json:"loader"` - ServerDetails struct { - Slc string `json:"slc"` - Dc string `json:"dc"` - Ri string `json:"ri"` - Ver struct { - V []int `json:"v"` - } `json:"ver"` - Rt string `json:"rt"` - Et int `json:"et"` - } `json:"serverDetails"` - Country string `json:"country"` - FBreakBrandingSigninString bool `json:"fBreakBrandingSigninString"` - Bsso struct { - Type string `json:"type"` - Reason string `json:"reason"` - } `json:"bsso"` - URLNoCookies string `json:"urlNoCookies"` - FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` + IRemoteNgcPollingType int `json:"iRemoteNgcPollingType"` + FUseNewNoPasswordTypes bool `json:"fUseNewNoPasswordTypes"` + URLAadSignup string `json:"urlAadSignup"` + URLOidcDiscoveryEndpointFormat string `json:"urlOidcDiscoveryEndpointFormat"` + URLTenantedEndpointFormat string `json:"urlTenantedEndpointFormat"` + SCloudInstanceName string `json:"sCloudInstanceName"` + FShowSignInOptionsAsButton bool `json:"fShowSignInOptionsAsButton"` + FUpdateLoginHint bool `json:"fUpdateLoginHint"` + IMaxStackForKnockoutAsyncComponents int `json:"iMaxStackForKnockoutAsyncComponents"` + FShowButtons bool `json:"fShowButtons"` + URLCdn string `json:"urlCdn"` + URLDefaultFavicon string `json:"urlDefaultFavicon"` + URLFooterTOU string `json:"urlFooterTOU"` + URLFooterPrivacy string `json:"urlFooterPrivacy"` + URLPost string `json:"urlPost"` + URLRefresh string `json:"urlRefresh"` + URLCancel string `json:"urlCancel"` + URLResume string `json:"urlResume"` + IPawnIcon int `json:"iPawnIcon"` + IPollingInterval int `json:"iPollingInterval"` + SPOSTUsername string `json:"sPOST_Username"` + SFT string `json:"sFT"` + SFTName string `json:"sFTName"` + SSessionIdentifierName string `json:"sSessionIdentifierName"` + SCtx string `json:"sCtx"` + IProductIcon int `json:"iProductIcon"` + URLReportPageLoad string `json:"urlReportPageLoad"` + ArrSessions []interface{} `json:"arrSessions"` + FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` + URLLogin string `json:"urlLogin"` + URLDssoStatus string `json:"urlDssoStatus"` + FUseSameSite bool `json:"fUseSameSite"` + IAllowedIdentities int `json:"iAllowedIdentities"` + IsGlobalTenant bool `json:"isGlobalTenant"` + FOfflineAccountVisible bool `json:"fOfflineAccountVisible"` + ScriptNonce string `json:"scriptNonce"` + FEnableUserStateFix bool `json:"fEnableUserStateFix"` + FAccessPassSupported bool `json:"fAccessPassSupported"` + FShowAccessPassPeek bool `json:"fShowAccessPassPeek"` + FUpdateSessionPollingLogic bool `json:"fUpdateSessionPollingLogic"` + Scid int `json:"scid"` + Hpgact int `json:"hpgact"` + Hpgid int `json:"hpgid"` + Pgid string `json:"pgid"` + APICanary string `json:"apiCanary"` + Canary string `json:"canary"` + CorrelationID string `json:"correlationId"` + SessionID string `json:"sessionId"` + SlMaxRetry int `json:"slMaxRetry"` + SlReportFailure bool `json:"slReportFailure"` + Country string `json:"country"` + URLNoCookies string `json:"urlNoCookies"` + FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` + InlineMode int `json:"inlineMode"` } -// Autogenerate password login response -// some case, some fields is not exists -type passwordLoginResponse struct { - ArrUserProofs []userProof `json:"arrUserProofs"` - FHideIHaveCodeLink bool `json:"fHideIHaveCodeLink"` - OPerAuthPollingInterval map[string]float64 `json:"oPerAuthPollingInterval"` - FProofIndexedByType bool `json:"fProofIndexedByType"` - URLBeginAuth string `json:"urlBeginAuth"` - URLEndAuth string `json:"urlEndAuth"` - ISAMode int `json:"iSAMode"` - ITrustedDeviceCheckboxConfig int `json:"iTrustedDeviceCheckboxConfig"` - IMaxPollAttempts int `json:"iMaxPollAttempts"` - IPollingTimeout int `json:"iPollingTimeout"` - IPollingBackoffInterval float64 `json:"iPollingBackoffInterval"` - IRememberMfaDuration float64 `json:"iRememberMfaDuration"` - STrustedDeviceCheckboxName string `json:"sTrustedDeviceCheckboxName"` - SAuthMethodInputFieldName string `json:"sAuthMethodInputFieldName"` - ISAOtcLength int `json:"iSAOtcLength"` - ITotpOtcLength int `json:"iTotpOtcLength"` - URLMoreInfo string `json:"urlMoreInfo"` - FShowViewDetailsLink bool `json:"fShowViewDetailsLink"` - FAlwaysUpdateFTInSasEnd bool `json:"fAlwaysUpdateFTInSasEnd"` - IMaxStackForKnockoutAsyncComponents int `json:"iMaxStackForKnockoutAsyncComponents"` - StrCopyrightTxt string `json:"strCopyrightTxt"` - FShowButtons bool `json:"fShowButtons"` - URLCdn string `json:"urlCdn"` - URLFooterTOU string `json:"urlFooterTOU"` - URLFooterPrivacy string `json:"urlFooterPrivacy"` - URLPost string `json:"urlPost"` - URLCancel string `json:"urlCancel"` - IPawnIcon int `json:"iPawnIcon"` - IPollingInterval int `json:"iPollingInterval"` - SPOSTUsername string `json:"sPOST_Username"` - SFT string `json:"sFT"` - SFTName string `json:"sFTName"` - SCtx string `json:"sCtx"` - DynamicTenantBranding []struct { - Locale int `json:"Locale"` - Illustration string `json:"Illustration"` - UserIDLabel string `json:"UserIdLabel"` - KeepMeSignedInDisabled bool `json:"KeepMeSignedInDisabled"` - UseTransparentLightBox bool `json:"UseTransparentLightBox"` - } `json:"dynamicTenantBranding"` - OAppCobranding struct { - } `json:"oAppCobranding"` - IBackgroundImage int `json:"iBackgroundImage"` - FUseConstantPolling bool `json:"fUseConstantPolling"` - FUseFlowTokenAsCanary bool `json:"fUseFlowTokenAsCanary"` - FApplicationInsightsEnabled bool `json:"fApplicationInsightsEnabled"` - IApplicationInsightsEnabledPercentage int `json:"iApplicationInsightsEnabledPercentage"` - URLSetDebugMode string `json:"urlSetDebugMode"` - FEnableCSSAnimation bool `json:"fEnableCssAnimation"` - FAllowGrayOutLightBox bool `json:"fAllowGrayOutLightBox"` - FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` - Scid int `json:"scid"` - Hpgact int `json:"hpgact"` - Hpgid int `json:"hpgid"` - Pgid string `json:"pgid"` - APICanary string `json:"apiCanary"` - Canary string `json:"canary"` - CorrelationID string `json:"correlationId"` - SessionID string `json:"sessionId"` - Locale struct { - Mkt string `json:"mkt"` - Lcid int `json:"lcid"` - } `json:"locale"` - SlMaxRetry int `json:"slMaxRetry"` - SlReportFailure bool `json:"slReportFailure"` - Strings struct { - Desktopsso struct { - Authenticatingmessage string `json:"authenticatingmessage"` - } `json:"desktopsso"` - } `json:"strings"` - Enums struct { - ClientMetricsModes struct { - None int `json:"None"` - SubmitOnPost int `json:"SubmitOnPost"` - SubmitOnRedirect int `json:"SubmitOnRedirect"` - InstrumentPlt int `json:"InstrumentPlt"` - } `json:"ClientMetricsModes"` - } `json:"enums"` - Urls struct { - Instr struct { - Pageload string `json:"pageload"` - Dssostatus string `json:"dssostatus"` - } `json:"instr"` - } `json:"urls"` - Browser struct { - Ltr int `json:"ltr"` - Other int `json:"_Other"` - Full int `json:"Full"` - REOther int `json:"RE_Other"` - B struct { - Name string `json:"name"` - Major int `json:"major"` - Minor int `json:"minor"` - } `json:"b"` - Os struct { - Name string `json:"name"` - Version string `json:"version"` - } `json:"os"` - V int `json:"V"` - } `json:"browser"` - Watson struct { - URL string `json:"url"` - Bundle string `json:"bundle"` - Sbundle string `json:"sbundle"` - Fbundle string `json:"fbundle"` - ResetErrorPeriod int `json:"resetErrorPeriod"` - MaxCorsErrors int `json:"maxCorsErrors"` - MaxInjectErrors int `json:"maxInjectErrors"` - MaxErrors int `json:"maxErrors"` - MaxTotalErrors int `json:"maxTotalErrors"` - ExpSrcs []string `json:"expSrcs"` - EnvErrorRedirect bool `json:"envErrorRedirect"` - EnvErrorURL string `json:"envErrorUrl"` - } `json:"watson"` - Loader struct { - CdnRoots []string `json:"cdnRoots"` - } `json:"loader"` - ServerDetails struct { - Slc string `json:"slc"` - Dc string `json:"dc"` - Ri string `json:"ri"` - Ver struct { - V []int `json:"v"` - } `json:"ver"` - Rt string `json:"rt"` - Et int `json:"et"` - } `json:"serverDetails"` - Country string `json:"country"` - FBreakBrandingSigninString bool `json:"fBreakBrandingSigninString"` - URLNoCookies string `json:"urlNoCookies"` - FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` +// Autogenerated GetCredentialType Request struct +// for some cases, some fields may not exist +type GetCredentialTypeRequest struct { + Username string `json:"username"` + IsOtherIdpSupported bool `json:"isOtherIdpSupported"` + CheckPhones bool `json:"checkPhones"` + IsRemoteNGCSupported bool `json:"isRemoteNGCSupported"` + IsCookieBannerShown bool `json:"isCookieBannerShown"` + IsFidoSupported bool `json:"isFidoSupported"` + OriginalRequest string `json:"originalRequest"` + Country string `json:"country"` + Forceotclogin bool `json:"forceotclogin"` + IsExternalFederationDisallowed bool `json:"isExternalFederationDisallowed"` + IsRemoteConnectSupported bool `json:"isRemoteConnectSupported"` + FederationFlags int `json:"federationFlags"` + IsSignup bool `json:"isSignup"` + FlowToken string `json:"flowToken"` + IsAccessPassSupported bool `json:"isAccessPassSupported"` } -// Autogenerated skip mfa login response -type SkipMfaResponse struct { - URLPostRedirect string `json:"urlPostRedirect"` - URLSkipMfaRegistration string `json:"urlSkipMfaRegistration"` - URLMoreInfo string `json:"urlMoreInfo"` - SProofUpToken string `json:"sProofUpToken"` - SProofUpTokenName string `json:"sProofUpTokenName"` - SProofUpAuthState string `json:"sProofUpAuthState"` - SCanaryToken string `json:"sCanaryToken"` - IRemainingDaysToSkipMfaRegistration int `json:"iRemainingDaysToSkipMfaRegistration"` +// Autogenerated GetCredentialType Response struct +// for some cases, some fields may not exist +type GetCredentialTypeResponse struct { + Username string `json:"Username"` + Display string `json:"Display"` + IfExistsResult int `json:"IfExistsResult"` + IsUnmanaged bool `json:"IsUnmanaged"` + ThrottleStatus int `json:"ThrottleStatus"` + Credentials struct { + PrefCredential int `json:"PrefCredential"` + HasPassword bool `json:"HasPassword"` + RemoteNgcParams interface{} `json:"RemoteNgcParams"` + FidoParams interface{} `json:"FidoParams"` + SasParams interface{} `json:"SasParams"` + CertAuthParams interface{} `json:"CertAuthParams"` + GoogleParams interface{} `json:"GoogleParams"` + FacebookParams interface{} `json:"FacebookParams"` + FederationRedirectURL string `json:"FederationRedirectUrl"` + } `json:"Credentials"` + FlowToken string `json:"FlowToken"` + IsSignupDisallowed bool `json:"IsSignupDisallowed"` + APICanary string `json:"apiCanary"` +} + +// Autogenerated Authentication Response struct +// for some cases, some fields may not exist +type AuthenticationResponse struct { IMaxStackForKnockoutAsyncComponents int `json:"iMaxStackForKnockoutAsyncComponents"` - StrCopyrightTxt string `json:"strCopyrightTxt"` FShowButtons bool `json:"fShowButtons"` URLCdn string `json:"urlCdn"` + URLDefaultFavicon string `json:"urlDefaultFavicon"` URLFooterTOU string `json:"urlFooterTOU"` URLFooterPrivacy string `json:"urlFooterPrivacy"` URLPost string `json:"urlPost"` - URLCancel string `json:"urlCancel"` IPawnIcon int `json:"iPawnIcon"` SPOSTUsername string `json:"sPOST_Username"` SFT string `json:"sFT"` SFTName string `json:"sFTName"` + SCtx string `json:"sCtx"` SCanaryTokenName string `json:"sCanaryTokenName"` - DynamicTenantBranding []struct { - Locale int `json:"Locale"` - Illustration string `json:"Illustration"` - UserIDLabel string `json:"UserIdLabel"` - KeepMeSignedInDisabled bool `json:"KeepMeSignedInDisabled"` - UseTransparentLightBox bool `json:"UseTransparentLightBox"` - } `json:"dynamicTenantBranding"` - OAppCobranding struct { - } `json:"oAppCobranding"` - IBackgroundImage int `json:"iBackgroundImage"` - FUseConstantPolling bool `json:"fUseConstantPolling"` - FUseFlowTokenAsCanary bool `json:"fUseFlowTokenAsCanary"` - FApplicationInsightsEnabled bool `json:"fApplicationInsightsEnabled"` - IApplicationInsightsEnabledPercentage int `json:"iApplicationInsightsEnabledPercentage"` - URLSetDebugMode string `json:"urlSetDebugMode"` - FEnableCSSAnimation bool `json:"fEnableCssAnimation"` - FAllowGrayOutLightBox bool `json:"fAllowGrayOutLightBox"` - FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` - Scid int `json:"scid"` - Hpgact int `json:"hpgact"` - Hpgid int `json:"hpgid"` - Pgid string `json:"pgid"` - APICanary string `json:"apiCanary"` - Canary string `json:"canary"` - CorrelationID string `json:"correlationId"` - SessionID string `json:"sessionId"` - Locale struct { - Mkt string `json:"mkt"` - Lcid int `json:"lcid"` - } `json:"locale"` - SlMaxRetry int `json:"slMaxRetry"` - SlReportFailure bool `json:"slReportFailure"` - Strings struct { - Desktopsso struct { - Authenticatingmessage string `json:"authenticatingmessage"` - } `json:"desktopsso"` - } `json:"strings"` - Enums struct { - ClientMetricsModes struct { - None int `json:"None"` - SubmitOnPost int `json:"SubmitOnPost"` - SubmitOnRedirect int `json:"SubmitOnRedirect"` - InstrumentPlt int `json:"InstrumentPlt"` - } `json:"ClientMetricsModes"` - } `json:"enums"` - Urls struct { - Instr struct { - Pageload string `json:"pageload"` - Dssostatus string `json:"dssostatus"` - } `json:"instr"` - } `json:"urls"` - Browser struct { - Ltr int `json:"ltr"` - Other int `json:"_Other"` - Full int `json:"Full"` - REOther int `json:"RE_Other"` - B struct { - Name string `json:"name"` - Major int `json:"major"` - Minor int `json:"minor"` - } `json:"b"` - Os struct { - Name string `json:"name"` - Version string `json:"version"` - } `json:"os"` - V int `json:"V"` - } `json:"browser"` - Watson struct { - URL string `json:"url"` - Bundle string `json:"bundle"` - Sbundle string `json:"sbundle"` - Fbundle string `json:"fbundle"` - ResetErrorPeriod int `json:"resetErrorPeriod"` - MaxCorsErrors int `json:"maxCorsErrors"` - MaxInjectErrors int `json:"maxInjectErrors"` - MaxErrors int `json:"maxErrors"` - MaxTotalErrors int `json:"maxTotalErrors"` - ExpSrcs []string `json:"expSrcs"` - EnvErrorRedirect bool `json:"envErrorRedirect"` - EnvErrorURL string `json:"envErrorUrl"` - } `json:"watson"` - Loader struct { - CdnRoots []string `json:"cdnRoots"` - } `json:"loader"` - ServerDetails struct { - Slc string `json:"slc"` - Dc string `json:"dc"` - Ri string `json:"ri"` - Ver struct { - V []int `json:"v"` - } `json:"ver"` - Rt string `json:"rt"` - Et int `json:"et"` - } `json:"serverDetails"` - Country string `json:"country"` - FBreakBrandingSigninString bool `json:"fBreakBrandingSigninString"` - URLNoCookies string `json:"urlNoCookies"` - FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` + FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` + FUseSameSite bool `json:"fUseSameSite"` + IsGlobalTenant bool `json:"isGlobalTenant"` + FOfflineAccountVisible bool `json:"fOfflineAccountVisible"` + ScriptNonce string `json:"scriptNonce"` + FEnableUserStateFix bool `json:"fEnableUserStateFix"` + FShowAccessPassPeek bool `json:"fShowAccessPassPeek"` + FUpdateSessionPollingLogic bool `json:"fUpdateSessionPollingLogic"` + Scid int `json:"scid"` + Hpgact int `json:"hpgact"` + Hpgid int `json:"hpgid"` + Pgid string `json:"pgid"` + APICanary string `json:"apiCanary"` + Canary string `json:"canary"` + CorrelationID string `json:"correlationId"` + SessionID string `json:"sessionId"` + SlMaxRetry int `json:"slMaxRetry"` + SlReportFailure bool `json:"slReportFailure"` + Country string `json:"country"` + URLNoCookies string `json:"urlNoCookies"` + FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` + InlineMode int `json:"inlineMode"` } -// mfa request +// Converged Response struct +type ConvergedResponse struct { + ArrUserProofs []userProof `json:"arrUserProofs"` + URLSkipMfaRegistration string `json:"urlSkipMfaRegistration"` + OPerAuthPollingInterval map[string]float64 `json:"oPerAuthPollingInterval"` + URLBeginAuth string `json:"urlBeginAuth"` + URLEndAuth string `json:"urlEndAuth"` + URLPost string `json:"urlPost"` + SPOSTUsername string `json:"sPOST_Username"` + SFT string `json:"sFT"` + SFTName string `json:"sFTName"` + SCtx string `json:"sCtx"` + Pgid string `json:"pgid"` +} + +// MFA Request struct type mfaRequest struct { AuthMethodID string `json:"AuthMethodId"` Method string `json:"Method"` @@ -473,7 +243,7 @@ type mfaRequest struct { AdditionalAuthData string `json:"AdditionalAuthData,omitempty"` } -// mfa response +// MFA Response struct type mfaResponse struct { Success bool `json:"Success"` ResultValue string `json:"ResultValue"` @@ -488,122 +258,6 @@ type mfaResponse struct { Timestamp time.Time `json:"Timestamp"` } -// Autogenerate ProcessAuth response -// some case, some fields is not exists -type processAuthResponse struct { - IMaxStackForKnockoutAsyncComponents int `json:"iMaxStackForKnockoutAsyncComponents"` - StrCopyrightTxt string `json:"strCopyrightTxt"` - FShowButtons bool `json:"fShowButtons"` - URLCdn string `json:"urlCdn"` - URLFooterTOU string `json:"urlFooterTOU"` - URLFooterPrivacy string `json:"urlFooterPrivacy"` - URLPost string `json:"urlPost"` - IPawnIcon int `json:"iPawnIcon"` - SPOSTUsername string `json:"sPOST_Username"` - SFT string `json:"sFT"` - SFTName string `json:"sFTName"` - SCtx string `json:"sCtx"` - SCanaryTokenName string `json:"sCanaryTokenName"` - DynamicTenantBranding []struct { - Locale int `json:"Locale"` - Illustration string `json:"Illustration"` - UserIDLabel string `json:"UserIdLabel"` - KeepMeSignedInDisabled bool `json:"KeepMeSignedInDisabled"` - UseTransparentLightBox bool `json:"UseTransparentLightBox"` - } `json:"dynamicTenantBranding"` - OAppCobranding struct { - } `json:"oAppCobranding"` - IBackgroundImage int `json:"iBackgroundImage"` - FUseConstantPolling bool `json:"fUseConstantPolling"` - FUseFlowTokenAsCanary bool `json:"fUseFlowTokenAsCanary"` - FApplicationInsightsEnabled bool `json:"fApplicationInsightsEnabled"` - IApplicationInsightsEnabledPercentage int `json:"iApplicationInsightsEnabledPercentage"` - URLSetDebugMode string `json:"urlSetDebugMode"` - FEnableCSSAnimation bool `json:"fEnableCssAnimation"` - FAllowGrayOutLightBox bool `json:"fAllowGrayOutLightBox"` - FIsRemoteNGCSupported bool `json:"fIsRemoteNGCSupported"` - Scid int `json:"scid"` - Hpgact int `json:"hpgact"` - Hpgid int `json:"hpgid"` - Pgid string `json:"pgid"` - APICanary string `json:"apiCanary"` - Canary string `json:"canary"` - CorrelationID string `json:"correlationId"` - SessionID string `json:"sessionId"` - Locale struct { - Mkt string `json:"mkt"` - Lcid int `json:"lcid"` - } `json:"locale"` - SlMaxRetry int `json:"slMaxRetry"` - SlReportFailure bool `json:"slReportFailure"` - Strings struct { - Desktopsso struct { - Authenticatingmessage string `json:"authenticatingmessage"` - } `json:"desktopsso"` - } `json:"strings"` - Enums struct { - ClientMetricsModes struct { - None int `json:"None"` - SubmitOnPost int `json:"SubmitOnPost"` - SubmitOnRedirect int `json:"SubmitOnRedirect"` - InstrumentPlt int `json:"InstrumentPlt"` - } `json:"ClientMetricsModes"` - } `json:"enums"` - Urls struct { - Instr struct { - Pageload string `json:"pageload"` - Dssostatus string `json:"dssostatus"` - } `json:"instr"` - } `json:"urls"` - Browser struct { - Ltr int `json:"ltr"` - Other int `json:"_Other"` - Full int `json:"Full"` - REOther int `json:"RE_Other"` - B struct { - Name string `json:"name"` - Major int `json:"major"` - Minor int `json:"minor"` - } `json:"b"` - Os struct { - Name string `json:"name"` - Version string `json:"version"` - } `json:"os"` - V int `json:"V"` - } `json:"browser"` - Watson struct { - URL string `json:"url"` - Bundle string `json:"bundle"` - Sbundle string `json:"sbundle"` - Fbundle string `json:"fbundle"` - ResetErrorPeriod int `json:"resetErrorPeriod"` - MaxCorsErrors int `json:"maxCorsErrors"` - MaxInjectErrors int `json:"maxInjectErrors"` - MaxErrors int `json:"maxErrors"` - MaxTotalErrors int `json:"maxTotalErrors"` - ExpSrcs []string `json:"expSrcs"` - EnvErrorRedirect bool `json:"envErrorRedirect"` - EnvErrorURL string `json:"envErrorUrl"` - } `json:"watson"` - Loader struct { - CdnRoots []string `json:"cdnRoots"` - } `json:"loader"` - ServerDetails struct { - Slc string `json:"slc"` - Dc string `json:"dc"` - Ri string `json:"ri"` - Ver struct { - V []int `json:"v"` - } `json:"ver"` - Rt string `json:"rt"` - Et int `json:"et"` - } `json:"serverDetails"` - Country string `json:"country"` - FBreakBrandingSigninString bool `json:"fBreakBrandingSigninString"` - URLNoCookies string `json:"urlNoCookies"` - FTrimChromeBssoURL bool `json:"fTrimChromeBssoUrl"` -} - // A given method for a user to prove their indentity type userProof struct { AuthMethodID string `json:"authMethodId"` @@ -642,328 +296,363 @@ func (ac *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) // startSAML startURL := fmt.Sprintf("%s/applications/redirecttofederatedapplication.aspx?Operation=LinkedSignIn&applicationId=%s", ac.idpAccount.URL, ac.idpAccount.AppID) - res, err := ac.client.Get(startURL) + convergedSignInResponse, res, err := ac.requestConvergedSignIn(startURL) if err != nil { - return samlAssertion, errors.Wrap(err, "error retrieving form") + return samlAssertion, errors.Wrap(err, "error processing ConvergedSignIn request") } - // data is embedded javascript object - // - */ - isEnabledConditonalAccess := strings.HasPrefix(resBodyStr, "Working...") && strings.Contains(resBodyStr, "name=\"flowtoken\"") + if ac.isHiddenForm(resBodyStr) { + resBodyStr, _, err = ac.reProcessForm(resBodyStr) + if err != nil { + return samlAssertion, errors.Wrap(err, "error processing hiddenform") + } + } - if isSkippedMFA || isEnabledConditonalAccess { - // require reprocess - if strings.Contains(resBodyStr, " - var loginPasswordJson string - if strings.Contains(resBodyStr, "$Config") { - loginPasswordJson = ac.getJsonFromConfig(resBodyStr) + if ac.isHiddenForm(resBodyStr) { + resBodyStr, res, err = ac.reProcessForm(resBodyStr) + if err != nil { + return samlAssertion, errors.Wrap(err, "error processing hiddenform") } - resBodyStr, err = ac.processAuth(loginPasswordJson, res) + } + + if strings.Contains(resBodyStr, "arrUserProofs") { + resBodyStr, err = ac.processAuth(resBodyStr, res) if err != nil { return samlAssertion, err } } - node, _ := html.Parse(strings.NewReader(resBodyStr)) - doc := goquery.NewDocumentFromNode(node) - - // data in input tag - authForm := url.Values{} - var authSubmitURL string - - doc.Find("input").Each(func(i int, s *goquery.Selection) { - name, ok := s.Attr("name") - if !ok { - return + for i := 0; i < 2; i++ { + // SAMLResponse should come in a form + samlAssertion, err = ac.getSamlAssertion(resBodyStr) + if err != nil { + return samlAssertion, errors.Wrap(err, "failed to read SAMLResponse") } - value, ok := s.Attr("value") - if !ok { - return + + if samlAssertion != "" { + return samlAssertion, nil } - authForm.Set(name, value) - }) - doc.Find("form").Each(func(i int, s *goquery.Selection) { - action, ok := s.Attr("action") - if !ok { - return + // form does not contain SAMLResponse, aim to get it from the submit response + if i < 1 { + resBodyStr, _, err = ac.reProcessForm(resBodyStr) + if err != nil { + return samlAssertion, errors.Wrap(err, "error processing hiddenform") + } } - authSubmitURL = action - }) + } - if authSubmitURL == "" { - return samlAssertion, fmt.Errorf("unable to locate IDP oidc form submit URL") + return samlAssertion, errors.New("failed get SAMLAssertion") +} + +func (ac *Client) requestConvergedSignIn(url string) (ConvergedSignInResponse, *http.Response, error) { + var res *http.Response + var err error + var resBodyStr string + var convergedSignInResponse ConvergedSignInResponse + + res, err = ac.client.Get(url) + if err != nil { + return convergedSignInResponse, res, errors.Wrap(err, "error retrieving ConvergedSignIn form") + } + + resBodyStr, _ = ac.responseBodyAsString(res.Body) + + if err := json.Unmarshal([]byte(ac.getJsonFromConfig(resBodyStr)), &convergedSignInResponse); err != nil { + return convergedSignInResponse, res, errors.Wrap(err, "ConvergedSignIn response unmarshal error") + } + + return convergedSignInResponse, res, nil +} + +func (ac *Client) requestGetCredentialType(refererUrl string, loginDetails *creds.LoginDetails, convergedSignInResponse ConvergedSignInResponse) (GetCredentialTypeResponse, *http.Response, error) { + var res *http.Response + var getCredentialTypeResponse GetCredentialTypeResponse + + reqBodyObj := GetCredentialTypeRequest{ + Username: loginDetails.Username, + IsOtherIdpSupported: true, + CheckPhones: false, + IsRemoteNGCSupported: false, + IsCookieBannerShown: false, + IsFidoSupported: false, + OriginalRequest: convergedSignInResponse.SCtx, + FlowToken: convergedSignInResponse.SFT, + } + reqBodyJson, err := json.Marshal(reqBodyObj) + if err != nil { + return getCredentialTypeResponse, res, errors.Wrap(err, "failed to build GetCredentialType request JSON") } - req, err := http.NewRequest("POST", authSubmitURL, strings.NewReader(authForm.Encode())) + req, err := http.NewRequest("POST", convergedSignInResponse.URLGetCredentialType, strings.NewReader(string(reqBodyJson))) if err != nil { - return samlAssertion, errors.Wrap(err, "error building authentication request") + return getCredentialTypeResponse, res, errors.Wrap(err, "error building GetCredentialType request") } - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("canary", convergedSignInResponse.APICanary) + req.Header.Add("client-request-id", convergedSignInResponse.CorrelationID) + req.Header.Add("hpgact", fmt.Sprint(convergedSignInResponse.Hpgact)) + req.Header.Add("hpgid", fmt.Sprint(convergedSignInResponse.Hpgid)) + req.Header.Add("hpgrequestid", convergedSignInResponse.SessionID) + req.Header.Add("Referer", refererUrl) - ac.client.EnableFollowRedirect() res, err = ac.client.Do(req) if err != nil { - return samlAssertion, errors.Wrap(err, "error retrieving oidc login form results") + return getCredentialTypeResponse, res, errors.Wrap(err, "error retrieving GetCredentialType results") } - // get saml assertion - oidcResponse, err := ioutil.ReadAll(res.Body) + err = json.NewDecoder(res.Body).Decode(&getCredentialTypeResponse) if err != nil { - return samlAssertion, errors.Wrap(err, "oidc login response error") + return getCredentialTypeResponse, res, errors.Wrap(err, "error decoding GetCredentialType results") } - oidcResponseStr := string(oidcResponse) + return getCredentialTypeResponse, res, nil +} - // data is embedded javascript - // window.location = 'https:/..../?SAMLRequest=......' - oidcResponseList := strings.Split(oidcResponseStr, ";") - var SAMLRequestURL string - for _, v := range oidcResponseList { - if strings.Contains(v, "SAMLRequest") { - startURLPos := strings.Index(v, "https://") - endURLPos := strings.Index(v[startURLPos:], "'") - if endURLPos == -1 { - endURLPos = strings.Index(v[startURLPos:], "\"") - } - SAMLRequestURL = v[startURLPos : startURLPos+endURLPos] - } +func (ac *Client) processADFSAuthentication(federationUrl string, loginDetails *creds.LoginDetails) (AuthenticationResponse, *http.Response, error) { + var res *http.Response + var err error + var resBodyStr string + var authenticationResponse AuthenticationResponse + var formValues url.Values + var formSubmitUrl string + var req *http.Request - } - if SAMLRequestURL == "" { - return samlAssertion, fmt.Errorf("unable to locate SAMLRequest URL") + res, err = ac.client.Get(federationUrl) + if err != nil { + return authenticationResponse, res, errors.Wrap(err, "error retrieving ADFS url") } - req, err = http.NewRequest("GET", SAMLRequestURL, nil) + resBodyStr, _ = ac.responseBodyAsString(res.Body) + + formValues, formSubmitUrl, err = ac.reSubmitFormData(resBodyStr) if err != nil { - return samlAssertion, errors.Wrap(err, "error building get request") + return authenticationResponse, res, errors.Wrap(err, "failed to parse ADFS login form") } - res, err = ac.client.Do(req) + if formSubmitUrl == "" { + return authenticationResponse, res, fmt.Errorf("unable to locate ADFS form submit URL") + } + + formValues.Set("UserName", loginDetails.Username) + formValues.Set("Password", loginDetails.Password) + formValues.Set("AuthMethod", "FormsAuthentication") + + req, err = http.NewRequest("POST", ac.fullUrl(res, formSubmitUrl), strings.NewReader(formValues.Encode())) if err != nil { - return samlAssertion, errors.Wrap(err, "error retrieving oidc login form results") + return authenticationResponse, res, errors.Wrap(err, "error building ADFS login request") } - // if mfa skipped then get $Config and urlSkipMfaRegistration - // get urlSkipMfaRegistraition to return saml assertion - resBodyStr, err = ac.responseBodyAsString(res.Body) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + res, err = ac.client.Do(req) if err != nil { - return samlAssertion, errors.Wrap(err, "error oidc login response read") + return authenticationResponse, res, errors.Wrap(err, "error retrieving ADFS login results") } - if strings.Contains(resBodyStr, "arrUserProofs") { - // data is embedded javascript object - // + + + + + + + + + +
+

JavaScript required

+

JavaScript is required. This web browser does not support JavaScript or JavaScript in this web browser is not enabled.

+

To find out if your web browser supports JavaScript or to enable JavaScript, see web browser help.

+
+ +
+
+
+
+
+
+ +
+
+ +
+ + + +
+
Sign in
+ +
+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ Sign in +
+
+ +
+ +
+
+ + + + +
+
+ +
+ introduction +
+ + +
+ +
+ +
+
+
+
+
+ +
+
+
+ + + + + + diff --git a/pkg/provider/aad/testdata/ADFStrust.html b/pkg/provider/aad/testdata/ADFStrust.html new file mode 100644 index 000000000..4819c5a5f --- /dev/null +++ b/pkg/provider/aad/testdata/ADFStrust.html @@ -0,0 +1 @@ +Working...
\ No newline at end of file diff --git a/pkg/provider/aad/testdata/BeginAuth.json b/pkg/provider/aad/testdata/BeginAuth.json new file mode 100644 index 000000000..bd38ad592 --- /dev/null +++ b/pkg/provider/aad/testdata/BeginAuth.json @@ -0,0 +1 @@ +{"Success":true,"ResultValue":"Success","Message":null,"AuthMethodId":"OneWaySMS","ErrCode":0,"Retry":false,"FlowToken":"{{.SFT}}","Ctx":"{{.Ctx}}","SessionId":"{{.SessionId}}","CorrelationId":"{{.ClientRequestId}}","Timestamp":"2020-01-01T00:00:00Z","Entropy":0} \ No newline at end of file diff --git a/pkg/provider/aad/testdata/ConvergedProofUpRedirect.html b/pkg/provider/aad/testdata/ConvergedProofUpRedirect.html new file mode 100644 index 000000000..045e1facd --- /dev/null +++ b/pkg/provider/aad/testdata/ConvergedProofUpRedirect.html @@ -0,0 +1,73 @@ + + + + + + + Sign in to your account + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkg/provider/aad/testdata/ConvergedSignIn.html b/pkg/provider/aad/testdata/ConvergedSignIn.html new file mode 100644 index 000000000..5d1779633 --- /dev/null +++ b/pkg/provider/aad/testdata/ConvergedSignIn.html @@ -0,0 +1,75 @@ + + + + + + + Sign in to your account + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkg/provider/aad/testdata/ConvergedTFA.html b/pkg/provider/aad/testdata/ConvergedTFA.html new file mode 100644 index 000000000..f55cb0400 --- /dev/null +++ b/pkg/provider/aad/testdata/ConvergedTFA.html @@ -0,0 +1,74 @@ + + + + + + + Sign in to your account + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkg/provider/aad/testdata/EndAuth.json b/pkg/provider/aad/testdata/EndAuth.json new file mode 100644 index 000000000..bd38ad592 --- /dev/null +++ b/pkg/provider/aad/testdata/EndAuth.json @@ -0,0 +1 @@ +{"Success":true,"ResultValue":"Success","Message":null,"AuthMethodId":"OneWaySMS","ErrCode":0,"Retry":false,"FlowToken":"{{.SFT}}","Ctx":"{{.Ctx}}","SessionId":"{{.SessionId}}","CorrelationId":"{{.ClientRequestId}}","Timestamp":"2020-01-01T00:00:00Z","Entropy":0} \ No newline at end of file diff --git a/pkg/provider/aad/testdata/GetCredentialType_adfs.json b/pkg/provider/aad/testdata/GetCredentialType_adfs.json new file mode 100644 index 000000000..adadb936f --- /dev/null +++ b/pkg/provider/aad/testdata/GetCredentialType_adfs.json @@ -0,0 +1 @@ +{"Username":"{{.UserName}}","Display":"{{.UserName}}","IfExistsResult":0,"IsUnmanaged":false,"ThrottleStatus":1,"Credentials":{"PrefCredential":4,"HasPassword":true,"RemoteNgcParams":null,"FidoParams":null,"SasParams":null,"CertAuthParams":null,"GoogleParams":null,"FacebookParams":null,"FederationRedirectUrl":"{{.UrlFederationRedirect}}"},"EstsProperties":{"UserTenantBranding":[{"Locale":0,"BannerLogo":"https://via.placeholder.com/280x60.png","TileLogo":"https://via.placeholder.com/240x240.png","TileDarkLogo":"https://via.placeholder.com/240x240.png","UserIdLabel":"someone@example.com","KeepMeSignedInDisabled":false,"UseTransparentLightBox":false,"LayoutTemplateConfig":{"showHeader":false,"headerLogo":"","layoutType":0,"hideCantAccessYourAccount":false,"hideForgotMyPassword":false,"hideResetItNow":false,"hideAccountResetCredentials":false,"showFooter":true,"hideTOU":false,"hidePrivacy":false},"CustomizationFiles":{"strings":{"adminConsent":"","attributeCollection":"","authenticatorNudgeScreen":"","conditionalAccess":""},"customCssUrl":""}}],"DomainType":4},"FlowToken":"{{.SFT}}","IsSignupDisallowed":true,"apiCanary":"{{.ApiCanary}}"} \ No newline at end of file diff --git a/pkg/provider/aad/testdata/GetCredentialType_default.json b/pkg/provider/aad/testdata/GetCredentialType_default.json new file mode 100644 index 000000000..ef5811a92 --- /dev/null +++ b/pkg/provider/aad/testdata/GetCredentialType_default.json @@ -0,0 +1 @@ +{"Username":"{{.UserName}}","Display":"{{.UserName}}","IfExistsResult":0,"IsUnmanaged":false,"ThrottleStatus":0,"Credentials":{"PrefCredential":1,"HasPassword":true,"RemoteNgcParams":null,"FidoParams":null,"SasParams":null,"CertAuthParams":null,"GoogleParams":null,"FacebookParams":null},"EstsProperties":{"UserTenantBranding":null,"DomainType":3},"FlowToken":"{{.SFT}}","IsSignupDisallowed":true,"apiCanary":"{{.ApiCanary}}"} \ No newline at end of file diff --git a/pkg/provider/aad/testdata/HiddenForm.html b/pkg/provider/aad/testdata/HiddenForm.html new file mode 100644 index 000000000..b47150d3c --- /dev/null +++ b/pkg/provider/aad/testdata/HiddenForm.html @@ -0,0 +1 @@ +Working...
\ No newline at end of file diff --git a/pkg/provider/aad/testdata/KmsiInterrupt.html b/pkg/provider/aad/testdata/KmsiInterrupt.html new file mode 100644 index 000000000..a4eb86a1d --- /dev/null +++ b/pkg/provider/aad/testdata/KmsiInterrupt.html @@ -0,0 +1,73 @@ + + + + + + + Sign in to your account + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkg/provider/aad/testdata/SAMLRequest.html b/pkg/provider/aad/testdata/SAMLRequest.html new file mode 100644 index 000000000..9d39c270b --- /dev/null +++ b/pkg/provider/aad/testdata/SAMLRequest.html @@ -0,0 +1,211 @@ + + + + + + + + + + + + +
+
+ + + +
+ + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+
+
+ +
+ + + + + +
+ +
+
+
+
+
+ +
+ +
+
+
+ + + + + + + + +
+ + + + diff --git a/pkg/provider/aad/testdata/SAMLResponse.html b/pkg/provider/aad/testdata/SAMLResponse.html new file mode 100644 index 000000000..be028ef01 --- /dev/null +++ b/pkg/provider/aad/testdata/SAMLResponse.html @@ -0,0 +1 @@ +Working...
\ No newline at end of file diff --git a/pkg/provider/aad/testdata/SAMLResponse.xml b/pkg/provider/aad/testdata/SAMLResponse.xml new file mode 100644 index 000000000..aaba12d27 --- /dev/null +++ b/pkg/provider/aad/testdata/SAMLResponse.xml @@ -0,0 +1,94 @@ + + https://sts.windows.net/25f4519b-eca5-405d-b516-123af862c268/ + + + + + + https://sts.windows.net/25f4519b-eca5-405d-b516-123af862c268/ + + + + + + + + + + + ba0vLeerzPU5SlBzNMQ95WNLauGojdAZBDdCPMJmUNI= + + + QE4db1da3PKU583Q0mm9MRpLaogENs95eWSkc8RvtU3kYwOVHpFtcVyG0wti54sc72V7rWSr3UoIGysgx_-3UJch_oG1JJi7IdNLhbFBx-PVxtAKvIdMkSM8tXRLuEtkNUB760jQAmie43Che8j47JdyWp4nh19QTDHjpH2vW9zldp-mhlLtl_QQQ-lJPd-LWC3A4xS0a81fenApzq4KvOY4zghapNih_dZOH6OO_UBgq_fyZ-x7gDiHin4UeySsaHQEBPr_mx5t6ilteSjm3J6HKlVVw9HNhmgry80UJkuVZ-7nWfgaawNjHDtG2UXN9k5oT0hCokMG7SlcPVKLqA== + + + MIIC8DCCAdigAwIBAgIQV3utGUh+Q55I54g7Y8RkUjANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDEylNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTAeFw0xOTA4MDgwNzA1MDBaFw0yMjA4MDgwNzAyMTlaMDQxMjAwBgNVBAMTKU1pY3Jvc29mdCBBenVyZSBGZWRlcmF0ZWQgU1NPIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApO5wQVjdzEx2/j5gNrUh94wpBni4wNmRI3tKoSWJpRjnnlhwHSiiAWo7KX924owbbc8m+aqZ/dt7gdyADl02dJN5vjYwHy0rJoitC6j9hVHd/Fz7QOOhlaLwtxKfp7bgzvLYw3/HsAFbnJxwQWdddiPm6+2b903tdUehV9lR7LgLwa8pYA8ybnV/8KrgB9zwDi8c+h0Od3+SLvheCagOLmPZBc3u2YkW6BRLt3HIdT75Rv5G81ak3yKdmpjelIgcj/39x/g5K4xTYYJz8x/a8xdy1tax46Vr0h7xfg3YkuYy/kcs6JGilQEVsA/NVmAGPl7W7uu03CCFsi5Xc8aIXwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBiVFSvDRTGqlgnBaQjrdaN3GanD+vggrz8rzm+ccdFi72xkRKMmAxePVcgYNZWl4pZgXitQOa9otE4gxzLFQEXpShj/xgomZ1orF5Fx2DIP/TtHn+6BGK4pi/QsSDWqOx33lDnPjXY6Ouiyz4GoY50l6UfXzwyCiYBoI/r0Paf5bLSF9gV0aJInFswG28lXDsUydXKsByrprqvYpWX6lplRf/SgCmCf8l9eApk+558cWtIlUn1mDzYxt8z7X8xhBYXyg6193wz4A2ULhfB7No/bO6WDlaaK2YN1VSpjRdwDKpKiR2yy3kJRJl1IO8szqIYPKcrdTwGBNRDix1UEwdR + + + + + exampleuser@exampledomain.com + + + + + + + https://signin.aws.amazon.com/saml + + + + + 25f4519b-eca5-405d-b516-123af862c268 + + + 5159e491-c7a1-4c67-bff9-666cdab9a60b + + + Doe, John + + + https://sts.windows.net/25f4519b-eca5-405d-b516-123af862c268/ + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + http://schemas.microsoft.com/claims/multipleauthn + + + arn:aws:iam::012345678901:role/example_role,arn:aws:iam::012345678901:saml-provider/EXAMPLE_PROVIDER + arn:aws:iam::123456789012:role/example_role,arn:aws:iam::123456789012:saml-provider/EXAMPLE_PROVIDER + + + John + + + Doe + + + john.doe@exampledomain.com + + + exampleuser@exampledomain.com + + + arn:aws:iam::012345678901:role/example_role,arn:aws:iam::012345678901:saml-provider/EXAMPLE_PROVIDER + arn:aws:iam::123456789012:role/example_role,arn:aws:iam::123456789012:saml-provider/EXAMPLE_PROVIDER + + + exampleuser@exampledomain.com + + + exampleuser + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + \ No newline at end of file From 89e7f4abf5c85c7d748c5e00d3ab7638faf54ec4 Mon Sep 17 00:00:00 2001 From: Chris Reeves Date: Fri, 6 May 2022 12:43:50 +0100 Subject: [PATCH 08/54] Fix Duo authentication failure with Shib provider Duo now appears to require the Accept-Language header to be present, otherwise it will produce an error. Fixes #818 --- pkg/provider/shibboleth/shibboleth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/provider/shibboleth/shibboleth.go b/pkg/provider/shibboleth/shibboleth.go index 678afbbb0..a9d058ee1 100644 --- a/pkg/provider/shibboleth/shibboleth.go +++ b/pkg/provider/shibboleth/shibboleth.go @@ -196,6 +196,7 @@ func verifyDuoMfa(oc *Client, loginDetails *creds.LoginDetails, duoHost string, req.URL.RawQuery = q.Encode() req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Accept-Language", "en-us,en;q=0.5") res, err := oc.client.Do(req) if err != nil { From d457de2ead280b5f019e2fcff357b2e8b754e40e Mon Sep 17 00:00:00 2001 From: Chris Reeves Date: Fri, 6 May 2022 12:47:49 +0100 Subject: [PATCH 09/54] Update README for Shibboleth provider Now tested against Shibboleth 4.2.1 --- pkg/provider/shibboleth/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/provider/shibboleth/README.md b/pkg/provider/shibboleth/README.md index 8b79d8cc9..29ff9db3d 100644 --- a/pkg/provider/shibboleth/README.md +++ b/pkg/provider/shibboleth/README.md @@ -16,4 +16,4 @@ https://idp.example.com/idp/profile/SAML2/Unsolicited/SSO?providerId=urn:amazon: * Tested on: * Shibboleth 3.3 with Duo MFA; - * Shibboleth 4.0.1 with Duo MFA and CSRF tokens. + * Shibboleth 4.0.1, 4.2.1 with Duo MFA and CSRF tokens. From 146fea1b38985237403540631fbc5a5bec2787a5 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:40:17 -0500 Subject: [PATCH 10/54] add support for building Windows MSI --- .github/win-msi/out/.gitignore | 2 ++ .github/win-msi/src/saml2aws.wxs | 28 ++++++++++++++++++ .github/win-msi/wix.sh | 3 ++ .github/workflows/release.yml | 50 +++++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 .github/win-msi/out/.gitignore create mode 100644 .github/win-msi/src/saml2aws.wxs create mode 100644 .github/win-msi/wix.sh diff --git a/.github/win-msi/out/.gitignore b/.github/win-msi/out/.gitignore new file mode 100644 index 000000000..1287e9bd7 --- /dev/null +++ b/.github/win-msi/out/.gitignore @@ -0,0 +1,2 @@ +** +!.gitignore diff --git a/.github/win-msi/src/saml2aws.wxs b/.github/win-msi/src/saml2aws.wxs new file mode 100644 index 000000000..f1b2c8571 --- /dev/null +++ b/.github/win-msi/src/saml2aws.wxs @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/win-msi/wix.sh b/.github/win-msi/wix.sh new file mode 100644 index 000000000..cbf8dc092 --- /dev/null +++ b/.github/win-msi/wix.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +candle src/saml2aws.wxs -dSaml2AwsVer=${VERSION} -o "out/" +light -sval "out/saml2aws.wixobj" -o "out/saml2aws_${VERSION}_windows_amd64.msi" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index be7f776f2..eadd358e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: jobs: release: name: release - runs-on: macOS-latest + runs-on: macos-latest steps: - name: Set up Go 1.x @@ -26,3 +26,51 @@ jobs: args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + windows-msi: + name: Build Windows MSI and upload to release + runs-on: ubuntu-latest + needs: [release] + env: + INSTALLER: win-msi + BIN: win-msi/src/bin + WIXIMG: dactiv/wix@sha256:17d232708589641f5632f9a1ff9463ad087b192cea7b8e6012d2b47ec6af5f6c + steps: + - name: Strip v from version tag + run: | + VER=${{ github.ref }} + VERSION=${VER//v} + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_EVENT + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: 1.17.x + + - name: Check out code + uses: actions/checkout@v2 + + - name: Retrieve the release asset + id: asset + uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 + with: + tag: ${{ github.ref }} + file: ${{ env.ASSET }} + out-file-path: ${{ env.BIN }} + + - name: Unzip asset + working-directory: ${{ env.BIN }} + run: unzip "${ASSET}" + + - name: Build MSI + run: | + # container does not run as root + chmod -R o+rw "${INSTALLER}" + + cat "${INSTALLER}/wix.sh" | docker run --rm -i -e VERSION -v "${INSTALLER}:/wix" ${WIXIMG} /bin/sh + + - name: Upload the asset to the release + uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14 / v1 + with: + files: ${{ env.INSTALLER }}/out/*.msi From 7cfcc685915d9009564ab0c02ddafd991efae2eb Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:41:39 -0500 Subject: [PATCH 11/54] fix paths --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eadd358e1..68a479d6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,8 +32,8 @@ jobs: runs-on: ubuntu-latest needs: [release] env: - INSTALLER: win-msi - BIN: win-msi/src/bin + INSTALLER: .github/win-msi + BIN: .github/win-msi/src/bin WIXIMG: dactiv/wix@sha256:17d232708589641f5632f9a1ff9463ad087b192cea7b8e6012d2b47ec6af5f6c steps: - name: Strip v from version tag From 37981185738fc69125777631f58d5840b1ae86fc Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:49:14 -0500 Subject: [PATCH 12/54] fix env file --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68a479d6a..6a2706af2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,7 +41,7 @@ jobs: VER=${{ github.ref }} VERSION=${VER//v} echo "VERSION=$VERSION" >> $GITHUB_ENV - echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_EVENT + echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV - name: Set up Go 1.x uses: actions/setup-go@v2 From 4a4bdadfeb457f79c18fdd6223b4e34e5f57a57a Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:58:39 -0500 Subject: [PATCH 13/54] fix download action parameter --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a2706af2..beb3bf6b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 with: tag: ${{ github.ref }} - file: ${{ env.ASSET }} + fileName: ${{ env.ASSET }} out-file-path: ${{ env.BIN }} - name: Unzip asset From 3c44353c4b14b8b8e4fdf126d360c6d022e0b36c Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 17:12:54 -0500 Subject: [PATCH 14/54] fix repository parameter --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index beb3bf6b9..40873d116 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,6 +55,7 @@ jobs: id: asset uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 with: + repository: ${{ github.repository }} tag: ${{ github.ref }} fileName: ${{ env.ASSET }} out-file-path: ${{ env.BIN }} From 01c61f6809f5cd6036bbb2a2cc77e42a596d9767 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 17:39:37 -0500 Subject: [PATCH 15/54] fix tag references --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 40873d116..d3ccfc3f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Strip v from version tag run: | - VER=${{ github.ref }} + VER=${GITHUB_REF/refs\/tags\//} VERSION=${VER//v} echo "VERSION=$VERSION" >> $GITHUB_ENV echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV @@ -56,7 +56,7 @@ jobs: uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 with: repository: ${{ github.repository }} - tag: ${{ github.ref }} + tag: ${{ env:VER }} fileName: ${{ env.ASSET }} out-file-path: ${{ env.BIN }} From ee6f185aa3766fe35e428541b1045e5d5a2fd095 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 17:40:22 -0500 Subject: [PATCH 16/54] typo --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3ccfc3f6..bfb42ee1b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 with: repository: ${{ github.repository }} - tag: ${{ env:VER }} + tag: ${{ env.VER }} fileName: ${{ env.ASSET }} out-file-path: ${{ env.BIN }} From 45be97bd0fe4cdf554601baada8ec9d46f058b2a Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 17:49:29 -0500 Subject: [PATCH 17/54] fix tag again --- .github/workflows/release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfb42ee1b..540601871 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,7 @@ on: jobs: release: + if: 'false' # testing name: release runs-on: macos-latest steps: @@ -30,7 +31,7 @@ jobs: windows-msi: name: Build Windows MSI and upload to release runs-on: ubuntu-latest - needs: [release] + # needs: [release] env: INSTALLER: .github/win-msi BIN: .github/win-msi/src/bin @@ -40,6 +41,7 @@ jobs: run: | VER=${GITHUB_REF/refs\/tags\//} VERSION=${VER//v} + echo "VER_TAG=$VER" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV @@ -56,7 +58,7 @@ jobs: uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 with: repository: ${{ github.repository }} - tag: ${{ env.VER }} + tag: ${{ env.VER_TAG }} fileName: ${{ env.ASSET }} out-file-path: ${{ env.BIN }} From d616ccf89d512f005de721a11e0a0e657e0b3c87 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 17:54:15 -0500 Subject: [PATCH 18/54] use full paths --- .github/workflows/release.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 540601871..b33487ee8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,8 +33,8 @@ jobs: runs-on: ubuntu-latest # needs: [release] env: - INSTALLER: .github/win-msi - BIN: .github/win-msi/src/bin + INSTALLER: ${{ github.workspace }}/.github/win-msi + BIN: ${{ github.workspace }}/.github/win-msi/src/bin WIXIMG: dactiv/wix@sha256:17d232708589641f5632f9a1ff9463ad087b192cea7b8e6012d2b47ec6af5f6c steps: - name: Strip v from version tag @@ -45,11 +45,6 @@ jobs: echo "VERSION=$VERSION" >> $GITHUB_ENV echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: 1.17.x - - name: Check out code uses: actions/checkout@v2 From e9c36410d91aca79bbe7f839cb4a6694be93634c Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:14:07 -0500 Subject: [PATCH 19/54] workflow dispatch --- .github/workflows/release.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b33487ee8..8cbe77178 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,12 +4,17 @@ on: push: tags: - '*' + workflow_dispatch: + inputs: + tag: + description: The tag to run against. If release exists, only the MSI builder runs. + required: true jobs: release: - if: 'false' # testing name: release runs-on: macos-latest + if: github.event_name != 'workflow_dispatch' steps: - name: Set up Go 1.x @@ -31,7 +36,8 @@ jobs: windows-msi: name: Build Windows MSI and upload to release runs-on: ubuntu-latest - # needs: [release] + needs: [release] + if: needs.release.result == 'success' || needs.release.result == 'skipped' env: INSTALLER: ${{ github.workspace }}/.github/win-msi BIN: ${{ github.workspace }}/.github/win-msi/src/bin From 9bf90ceffa719479cfd94dc2a568a1103868e78b Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:15:12 -0500 Subject: [PATCH 20/54] better description --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8cbe77178..4684a3b9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: inputs: tag: - description: The tag to run against. If release exists, only the MSI builder runs. + description: The tag to run against. This trigger only runs the MSI builder. required: true jobs: From ad42b302a5e3d5db99f66489741109c637b67b98 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:18:46 -0500 Subject: [PATCH 21/54] needs conditional --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4684a3b9e..cd0a95b97 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,9 @@ jobs: name: Build Windows MSI and upload to release runs-on: ubuntu-latest needs: [release] - if: needs.release.result == 'success' || needs.release.result == 'skipped' + if: >- # https://github.com/actions/runner/issues/491 + always() && + (needs.release.result == 'success' || needs.release.result == 'skipped') env: INSTALLER: ${{ github.workspace }}/.github/win-msi BIN: ${{ github.workspace }}/.github/win-msi/src/bin From 106519e861974fcb38dda728e92e898df7d04426 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:23:22 -0500 Subject: [PATCH 22/54] tag fixups --- .github/workflows/release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cd0a95b97..1d115182d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,10 +45,16 @@ jobs: BIN: ${{ github.workspace }}/.github/win-msi/src/bin WIXIMG: dactiv/wix@sha256:17d232708589641f5632f9a1ff9463ad087b192cea7b8e6012d2b47ec6af5f6c steps: - - name: Strip v from version tag + - name: Normalize tag values run: | - VER=${GITHUB_REF/refs\/tags\//} + if [[ "${{ github.event_name }}" == "workflow_dispatch "]] ; then + VER=${{ github.event.inputs.tag }} + else + VER=${GITHUB_REF/refs\/tags\//} + fi + VERSION=${VER//v} + echo "VER_TAG=$VER" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV @@ -79,4 +85,5 @@ jobs: - name: Upload the asset to the release uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14 / v1 with: + tag_name: ${{ env.VER_TAG }} files: ${{ env.INSTALLER }}/out/*.msi From 430d80fc7346f28bbe1cd2ef5b11edf1b1dddec5 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:25:12 -0500 Subject: [PATCH 23/54] bash me --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1d115182d..d1ddec7b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,7 +47,7 @@ jobs: steps: - name: Normalize tag values run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch "]] ; then + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]] ; then VER=${{ github.event.inputs.tag }} else VER=${GITHUB_REF/refs\/tags\//} From 2ce9149a092b48b4e4a83be55695484d37b2e68b Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 3 May 2022 17:44:53 -0400 Subject: [PATCH 24/54] Update .github/workflows/release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1ddec7b3..dbaee85e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,7 +60,7 @@ jobs: echo "ASSET=saml2aws_${VERSION}_windows_amd64.zip" >> $GITHUB_ENV - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Retrieve the release asset id: asset From c21240b2cf0ec93d7f0bfd1646d796df8299edb8 Mon Sep 17 00:00:00 2001 From: charltona <2724511+charltona@users.noreply.github.com> Date: Wed, 18 Jan 2023 09:46:01 +1000 Subject: [PATCH 25/54] Allow Symantec VIP to be passed as param for OTP method for okta signin --- saml2aws.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/saml2aws.go b/saml2aws.go index 010c42aca..678085380 100644 --- a/saml2aws.go +++ b/saml2aws.go @@ -37,10 +37,10 @@ var MFAsByProvider = ProviderList{ "Ping": []string{"Auto"}, // automatically detects PingID "PingOne": []string{"Auto"}, // automatically detects PingID "JumpCloud": []string{"Auto", "TOTP", "WEBAUTHN", "DUO", "PUSH"}, - "Okta": []string{"Auto", "PUSH", "DUO", "SMS", "TOTP", "OKTA", "FIDO", "YUBICO TOKEN:HARDWARE"}, // automatically detects DUO, SMS, ToTP, and FIDO - "OneLogin": []string{"Auto", "OLP", "SMS", "TOTP", "YUBIKEY"}, // automatically detects OneLogin Protect, SMS and ToTP - "KeyCloak": []string{"Auto"}, // automatically detects ToTP - "GoogleApps": []string{"Auto"}, // automatically detects ToTP + "Okta": []string{"Auto", "PUSH", "DUO", "SMS", "TOTP", "OKTA", "FIDO", "YUBICO TOKEN:HARDWARE", "SYMANTEC"}, // automatically detects DUO, SMS, ToTP, and FIDO + "OneLogin": []string{"Auto", "OLP", "SMS", "TOTP", "YUBIKEY"}, // automatically detects OneLogin Protect, SMS and ToTP + "KeyCloak": []string{"Auto"}, // automatically detects ToTP + "GoogleApps": []string{"Auto"}, // automatically detects ToTP "Shibboleth": []string{"Auto", "None"}, "F5APM": []string{"Auto"}, "Akamai": []string{"Auto", "DUO", "SMS", "EMAIL", "TOTP"}, From cc5d3f9380ad5b9f9843926fd4df62d816969230 Mon Sep 17 00:00:00 2001 From: falms Date: Tue, 14 Feb 2023 21:56:33 +0900 Subject: [PATCH 26/54] fix googleapps login use form data returned by server instead of hard-coded values --- pkg/provider/googleapps/googleapps.go | 78 +++------------------------ 1 file changed, 8 insertions(+), 70 deletions(-) diff --git a/pkg/provider/googleapps/googleapps.go b/pkg/provider/googleapps/googleapps.go index 7e8e6ad1f..3f99f089c 100644 --- a/pkg/provider/googleapps/googleapps.go +++ b/pkg/provider/googleapps/googleapps.go @@ -55,8 +55,12 @@ func (kc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) return "", errors.Wrap(err, "error loading first page") } + // Google supports only JavaScript-enabled clients + authForm.Set("bgresponse", "js_enabled") + authForm.Set("Email", loginDetails.Username) + // Post email address w/o password, then Get the password-input page passwordURL, passwordForm, err := kc.loadLoginPage(authURL+"?hl=en&loc=US", loginDetails.URL+"&hl=en&loc=US", authForm) if err != nil { return "", errors.Wrap(err, "error loading login page") @@ -64,23 +68,12 @@ func (kc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) logger.Debugf("loginURL: %s", passwordURL) - authForm.Set("Passwd", loginDetails.Password) + passwordForm.Set("Passwd", loginDetails.Password) + passwordForm.Set("TrustDevice", "on") referingURL := passwordURL - if _, rawIdPresent := passwordForm["rawidentifier"]; rawIdPresent { - authForm.Set("rawidentifier", loginDetails.Username) - referingURL = authURL - } - - if v, tlPresent := passwordForm["TL"]; tlPresent { - authForm.Set("TL", v[0]) - } - if v, gxfPresent := passwordForm["gxf"]; gxfPresent { - authForm.Set("gxf", v[0]) - } - - responseDoc, err := kc.loadChallengePage(passwordURL+"?hl=en&loc=US", referingURL, authForm, loginDetails) + responseDoc, err := kc.loadChallengePage(passwordURL+"?hl=en&loc=US", referingURL, passwordForm, loginDetails) if err != nil { return "", errors.Wrap(err, "error loading challenge page") } @@ -231,62 +224,7 @@ func (kc *Client) loadFirstPage(loginDetails *creds.LoginDetails) (string, url.V return "", nil, errors.Wrap(err, "failed to build login form data") } - _, loginPageV1 := authForm["GALX"] - - var postForm url.Values - // using a field which is known to be in the original login page - if loginPageV1 { - // Login page v1 - postForm = url.Values{ - "bgresponse": []string{"js_enabled"}, - "checkConnection": []string{""}, - "checkedDomains": []string{"youtube"}, - "continue": []string{authForm.Get("continue")}, - "gxf": []string{authForm.Get("gxf")}, - "identifier-captcha-input": []string{""}, - "identifiertoken": []string{""}, - "identifiertoken_audio": []string{""}, - "ltmpl": []string{"popup"}, - "oauth": []string{"1"}, - "Page": []string{authForm.Get("Page")}, - "Passwd": []string{""}, - "PersistentCookie": []string{"yes"}, - "ProfileInformation": []string{""}, - "pstMsg": []string{"0"}, - "sarp": []string{"1"}, - "scc": []string{"1"}, - "SessionState": []string{authForm.Get("SessionState")}, - "signIn": []string{authForm.Get("signIn")}, - "_utf8": []string{authForm.Get("_utf8")}, - "GALX": []string{authForm.Get("GALX")}, - } - } else { - // Login page v2 - postForm = url.Values{ - "challengeId": []string{"1"}, - "challengeType": []string{"1"}, - "continue": []string{authForm.Get("continue")}, - "scc": []string{"1"}, - "sarp": []string{"1"}, - "checkeddomains": []string{"youtube"}, - "checkConnection": []string{"youtube:930:1"}, - "pstMessage": []string{"1"}, - "oauth": []string{authForm.Get("oauth")}, - "flowName": []string{authForm.Get("flowName")}, - "faa": []string{"1"}, - "Email": []string{""}, - "Passwd": []string{""}, - "TrustDevice": []string{"on"}, - "bgresponse": []string{"js_enabled"}, - } - for _, k := range []string{"TL", "gxf"} { - if v, ok := authForm[k]; ok { - postForm.Set(k, v[0]) - } - } - } - - return submitURL, postForm, err + return submitURL, authForm, err } func (kc *Client) loadLoginPage(submitURL string, referer string, authForm url.Values) (string, url.Values, error) { From b1ea91909bd22c717009db2b751e2c54a27e648d Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Mon, 6 Mar 2023 14:48:52 -0500 Subject: [PATCH 27/54] bump action versions --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01fe904a8..97b0a5f6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,7 +76,7 @@ jobs: - name: Retrieve the release asset id: asset - uses: robinraju/release-downloader@4bdb8ee081c9ee08a35320794dd461312ac9e4ad # v1.3 + uses: robinraju/release-downloader@768b85c8d69164800db5fc00337ab917daf3ce68 # v1.7 with: repository: ${{ github.repository }} tag: ${{ env.VER_TAG }} @@ -95,7 +95,7 @@ jobs: cat "${INSTALLER}/wix.sh" | docker run --rm -i -e VERSION -v "${INSTALLER}:/wix" ${WIXIMG} /bin/sh - name: Upload the asset to the release - uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14 / v1 + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 / v1 with: tag_name: ${{ env.VER_TAG }} files: ${{ env.INSTALLER }}/out/*.msi From bd48521f0738c4ff9e9811998eabd82c445744bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 3 Mar 2023 20:58:55 -0500 Subject: [PATCH 28/54] Bump Golang to 1.19 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .appveyor/appveyor.yml | 4 ++-- .github/workflows/go.yml | 6 +++--- .github/workflows/release.yml | 2 +- go.mod | 2 +- pkg/provider/http_test.go | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index 50849831f..f25ece294 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -7,8 +7,8 @@ environment: secure: 3kWTz99Qj+ipyaR73CxcJeGRRbmk84MF2ERDu6MyY10cjHAi6s3AVZ2Ccoa+Ioyt appName: saml2aws install: -- set PATH=C:\msys64\mingw64\bin;C:\go118\bin;%PATH% -- set GOROOT=C:\go118 +- set PATH=C:\msys64\mingw64\bin;C:\go119\bin;%PATH% +- set GOROOT=C:\go119 - ps: >- $VerbosePreference = 'Continue' diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7f80570c2..f48f4952f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.19.x - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -38,7 +38,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.19.x - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -61,7 +61,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.19.x - name: Check out code into the Go module directory uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9a0d2867..207f9b22e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.19.x - name: Check out code into the Go module directory uses: actions/checkout@v3 diff --git a/go.mod b/go.mod index 1193856e0..fe02f0dec 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/versent/saml2aws/v2 -go 1.18 +go 1.19 require ( github.com/99designs/keyring v1.2.2 diff --git a/pkg/provider/http_test.go b/pkg/provider/http_test.go index 4cfe6c6e2..ee16b5216 100644 --- a/pkg/provider/http_test.go +++ b/pkg/provider/http_test.go @@ -49,8 +49,8 @@ func TestClientDisableRedirect(t *testing.T) { require.Nil(t, err) res, err := hc.Do(req) - require.Error(t, err) - require.Nil(t, res) + require.Nil(t, err) + require.Equal(t, 302, res.StatusCode) } func TestClientDoResponseCheck(t *testing.T) { From d3c49ec76102b6b6c388b2336ec21677793044d4 Mon Sep 17 00:00:00 2001 From: Rob Walsh Date: Thu, 9 Mar 2023 11:11:19 -0700 Subject: [PATCH 29/54] Update make instructions --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index b5d47ca2a..d2c8da4d6 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,19 @@ hash -r saml2aws --version ``` +#### Using Make + +You will need [Go Tools](https://golang.org/doc/install) (you can check your package maintainer as well) installed and the [Go Lint tool](https://github.com/alecthomas/gometalinter) + +Clone this repo to your `$GOPATH/src` directory + +Now you can install by running + +``` +make +make install +``` + #### [Arch Linux](https://archlinux.org/) and its derivatives The `saml2aws` tool is available in AUR ([saml2aws-bin](https://aur.archlinux.org/packages/saml2aws-bin/)), so you can install it using an available AUR helper: From 8117891881a9806078ec70e2284aee39dc61acd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 3 Mar 2023 20:58:55 -0500 Subject: [PATCH 30/54] Bump Golang to 1.20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .appveyor/appveyor.yml | 4 ++-- .github/workflows/go.yml | 6 +++--- .github/workflows/release.yml | 2 +- go.mod | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index f25ece294..391c75eaf 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -7,8 +7,8 @@ environment: secure: 3kWTz99Qj+ipyaR73CxcJeGRRbmk84MF2ERDu6MyY10cjHAi6s3AVZ2Ccoa+Ioyt appName: saml2aws install: -- set PATH=C:\msys64\mingw64\bin;C:\go119\bin;%PATH% -- set GOROOT=C:\go119 +- set PATH=C:\msys64\mingw64\bin;C:\go120\bin;%PATH% +- set GOROOT=C:\go120 - ps: >- $VerbosePreference = 'Continue' diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f48f4952f..be4d2cb59 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -38,7 +38,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -61,7 +61,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: Check out code into the Go module directory uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 207f9b22e..82c1c2d22 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: Check out code into the Go module directory uses: actions/checkout@v3 diff --git a/go.mod b/go.mod index 136013a9f..6eed08c77 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/versent/saml2aws/v2 -go 1.19 +go 1.20 require ( github.com/99designs/keyring v1.2.2 From aa5beeff9bb9ce723c14b13001258c25c37603aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 10 Mar 2023 22:28:17 -0500 Subject: [PATCH 31/54] Move playwright-go from mxschmitt to playwright-community MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- README.md | 2 +- go.mod | 4 ++-- go.sum | 7 ++++--- pkg/provider/browser/browser.go | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d2c8da4d6..c738da22a 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ The process goes something like this: * [Akamai](pkg/provider/akamai/README.md) * OneLogin * NetIQ - * Browser, this uses [playwright-go](github.com/mxschmitt/playwright-go) to run a sandbox chromium window. + * Browser, this uses [playwright-go](github.com/playwright-community/playwright-go) to run a sandbox chromium window. * [Auth0](pkg/provider/auth0/README.md) NOTE: Currently, MFA not supported * AWS SAML Provider configured diff --git a/go.mod b/go.mod index 6eed08c77..376763141 100644 --- a/go.mod +++ b/go.mod @@ -16,8 +16,8 @@ require ( github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621 github.com/marshallbrekka/go-u2fhost v0.0.0-20210111072507-3ccdec8c8105 github.com/mitchellh/go-homedir v1.1.0 - github.com/mxschmitt/playwright-go v0.1400.0 github.com/pkg/errors v0.9.1 + github.com/playwright-community/playwright-go v0.2000.1 github.com/sirupsen/logrus v1.9.0 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.8.2 @@ -35,8 +35,8 @@ require ( github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect - github.com/gorilla/websocket v1.4.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect diff --git a/go.sum b/go.sum index de4f48d5d..e0ab25153 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -73,7 +75,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -120,8 +121,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxschmitt/playwright-go v0.1400.0 h1:HL8dbxcVEobE+pNjASeYGJJRmd4+9gyu/51XO7d3qF0= -github.com/mxschmitt/playwright-go v0.1400.0/go.mod h1:kUvZFgMneRGknVLtC2DKQ42lhZiCmWzxgBdGwjC0vkw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -129,6 +128,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/playwright-community/playwright-go v0.2000.1 h1:2JViSHpJQ/UL/PO1Gg6gXV5IcXAAsoBJ3KG9L3wKXto= +github.com/playwright-community/playwright-go v0.2000.1/go.mod h1:1y9cM9b9dVHnuRWzED1KLM7FtbwTJC8ibDjI6MNqewU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= diff --git a/pkg/provider/browser/browser.go b/pkg/provider/browser/browser.go index d2947bfee..ff31cf75e 100644 --- a/pkg/provider/browser/browser.go +++ b/pkg/provider/browser/browser.go @@ -4,7 +4,7 @@ import ( "errors" "net/url" - "github.com/mxschmitt/playwright-go" + "github.com/playwright-community/playwright-go" "github.com/sirupsen/logrus" "github.com/versent/saml2aws/v2/pkg/cfg" "github.com/versent/saml2aws/v2/pkg/creds" From 7f4a3669e7a4604969a8d4d2e4484f472d7647a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 10 Mar 2023 22:46:21 -0500 Subject: [PATCH 32/54] Use --clean with goreleaser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .github/workflows/go.yml | 2 +- .github/workflows/release.yml | 2 +- Makefile | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index be4d2cb59..9746b03f4 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -74,4 +74,4 @@ jobs: uses: goreleaser/goreleaser-action@v4 with: version: latest - args: build --snapshot --rm-dist --config .goreleaser.${{ matrix.os }}.yml + args: build --snapshot --clean --config .goreleaser.${{ matrix.os }}.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 82c1c2d22..4f76f30ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,6 +35,6 @@ jobs: uses: goreleaser/goreleaser-action@v4 with: version: latest - args: release --rm-dist --config .goreleaser.${{ matrix.os }}.yml + args: release --clean --config .goreleaser.${{ matrix.os }}.yml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 5bcf4a70b..d3ece863e 100644 --- a/Makefile +++ b/Makefile @@ -38,9 +38,9 @@ install: build: $(BIN_DIR)/goreleaser ifeq ($(OS),Darwin) - $(BIN_DIR)/goreleaser build --snapshot --rm-dist --config $(CURDIR)/.goreleaser.macos-latest.yml + $(BIN_DIR)/goreleaser build --snapshot --clean --config $(CURDIR)/.goreleaser.macos-latest.yml else ifeq ($(OS),Linux) - $(BIN_DIR)/goreleaser build --snapshot --rm-dist --config $(CURDIR)/.goreleaser.ubuntu-latest.yml + $(BIN_DIR)/goreleaser build --snapshot --clean --config $(CURDIR)/.goreleaser.ubuntu-latest.yml else $(error Unsupported build OS: $(OS)) endif From 457322fae2f113d10a62b7bd10f787ee9c11895b Mon Sep 17 00:00:00 2001 From: falms Date: Sat, 11 Mar 2023 20:36:34 +0900 Subject: [PATCH 33/54] Add tests for extracting GoogleApps password form --- .../example/form-password-challengeid-1.html | 115 ++++++++++++++++++ .../example/form-password-challengeid-2.html | 115 ++++++++++++++++++ pkg/provider/googleapps/googleapps_test.go | 54 ++++++++ 3 files changed, 284 insertions(+) create mode 100644 pkg/provider/googleapps/example/form-password-challengeid-1.html create mode 100644 pkg/provider/googleapps/example/form-password-challengeid-2.html diff --git a/pkg/provider/googleapps/example/form-password-challengeid-1.html b/pkg/provider/googleapps/example/form-password-challengeid-1.html new file mode 100644 index 000000000..e8771fd7f --- /dev/null +++ b/pkg/provider/googleapps/example/form-password-challengeid-1.html @@ -0,0 +1,115 @@ + + + + + + + + + + Google Accounts + + +
+
+
+
+
+
+
+
+
+
+

One account. All of Google.

+

Sign in with your Google Account

+
+
+
+
+ + + + + + + + + + + + + + + +
+
+ + test-id1@example.com +
+ +
+ + +
+ +
+ + Stay signed in + +
+
+
+
+
+
+ + + + + + + + + + + + + + + +
+
+
+
+

Sign in with a different account

+

One Google Account for everything Google

+
+
+
+
+
+
+ +
+ + + +
+
+
+
+ + +
diff --git a/pkg/provider/googleapps/example/form-password-challengeid-2.html b/pkg/provider/googleapps/example/form-password-challengeid-2.html new file mode 100644 index 000000000..046c73c1e --- /dev/null +++ b/pkg/provider/googleapps/example/form-password-challengeid-2.html @@ -0,0 +1,115 @@ + + + + + + + + + + Google Accounts + + +
+
+
+
+
+
+
+
+
+
+

One account. All of Google.

+

Sign in with your Google Account

+
+
+
+
+ + + + + + + + + + + + + + + +
+
+ + test-id2@example.com +
+ +
+ + +
+ +
+ + Stay signed in + +
+
+
+
+
+
+ + + + + + + + + + + + + + + +
+
+
+
+

Sign in with a different account

+

One Google Account for everything Google

+
+
+
+
+
+
+ +
+ + + +
+
+
+
+ + +
diff --git a/pkg/provider/googleapps/googleapps_test.go b/pkg/provider/googleapps/googleapps_test.go index bb5bc53b1..d83a775b6 100644 --- a/pkg/provider/googleapps/googleapps_test.go +++ b/pkg/provider/googleapps/googleapps_test.go @@ -77,6 +77,60 @@ func TestContentContainsMessage2(t *testing.T) { require.Equal(t, "This extra step shows that it’s really you trying to sign in", txt) } +func TestPasswordFormChallengeId1(t *testing.T) { + data, err := os.ReadFile("example/form-password-challengeid-1.html") + require.Nil(t, err) + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(data) + })) + defer ts.Close() + + opts := &provider.HTTPClientOptions{IsWithRetries: false} + kc := Client{client: &provider.HTTPClient{Client: http.Client{}, Options: opts}} + loginDetails := &creds.LoginDetails{URL: ts.URL, Username: "test-id1@example.com", Password: "test123"} + + authForm := url.Values{} + authForm.Set("bgresponse", "js_enabled") + authForm.Set("Email", loginDetails.Username) + + passwordURL, passwordForm, err := kc.loadLoginPage(ts.URL, loginDetails.URL+"&hl=en&loc=US", authForm) + require.Nil(t, err) + require.NotEmpty(t, passwordURL) + require.Equal(t, "1", passwordForm.Get("challengeId")) + // check pre-filled email + require.NotEmpty(t, passwordForm.Get("Email")) + // check password form + require.Empty(t, passwordForm.Get("Passwd")) +} + +func TestPasswordFormChallengeId2(t *testing.T) { + data, err := os.ReadFile("example/form-password-challengeid-2.html") + require.Nil(t, err) + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(data) + })) + defer ts.Close() + + opts := &provider.HTTPClientOptions{IsWithRetries: false} + kc := Client{client: &provider.HTTPClient{Client: http.Client{}, Options: opts}} + loginDetails := &creds.LoginDetails{URL: ts.URL, Username: "test-id2@example.com", Password: "test123"} + + authForm := url.Values{} + authForm.Set("bgresponse", "js_enabled") + authForm.Set("Email", loginDetails.Username) + + passwordURL, passwordForm, err := kc.loadLoginPage(ts.URL, loginDetails.URL+"&hl=en&loc=US", authForm) + require.Nil(t, err) + require.NotEmpty(t, passwordURL) + require.Equal(t, "2", passwordForm.Get("challengeId")) + // check pre-filled email + require.NotEmpty(t, passwordForm.Get("Email")) + // check password form + require.Empty(t, passwordForm.Get("Passwd")) +} + func TestChallengePage(t *testing.T) { data, err := os.ReadFile("example/challenge-totp.html") From 070c1a2772e9bec158741e87aa4c20d934e2b136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Sun, 12 Mar 2023 11:01:54 -0400 Subject: [PATCH 34/54] Publish artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .github/workflows/go.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9746b03f4..16a89177e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -75,3 +75,9 @@ jobs: with: version: latest args: build --snapshot --clean --config .goreleaser.${{ matrix.os }}.yml + + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: saml2aws + path: dist/ From 780a541763162ba279f537adef0b1b925a92b3f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 20:59:30 +0000 Subject: [PATCH 35/54] chore(deps): bump github.com/aws/aws-sdk-go from 1.44.205 to 1.44.220 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.205 to 1.44.220. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.44.205...v1.44.220) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6eed08c77..0e802169f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/alecthomas/kingpin v2.2.6+incompatible github.com/avast/retry-go v3.0.0+incompatible - github.com/aws/aws-sdk-go v1.44.205 + github.com/aws/aws-sdk-go v1.44.220 github.com/beevik/etree v1.1.0 github.com/danieljoos/wincred v1.1.2 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index de4f48d5d..9a7e04fec 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/aws/aws-sdk-go v1.44.205 h1:q23NJXgLPIuBMn4zaluWWz57HPP5z7Ut8ZtK1D3N9bs= -github.com/aws/aws-sdk-go v1.44.205/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.220 h1:yAj99qAt0Htjle9Up3DglgHfOP77lmFPrElA4jKnrBo= +github.com/aws/aws-sdk-go v1.44.220/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/bearsh/hid v1.3.0 h1:GLNa8hvEzJxzQEEpheDUr2SivvH7iwTrJrDhFKutfX8= github.com/bearsh/hid v1.3.0/go.mod h1:KbQByg8WfPr92v7aaKAHTtZUEVG7e2XRpcF8+TopQv8= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= From 4252b01b854f44ae871dbaa8c48b7c649e0131a3 Mon Sep 17 00:00:00 2001 From: Hunter Date: Mon, 16 Jan 2023 09:24:03 +0000 Subject: [PATCH 36/54] feat: add Authentik provider --- pkg/provider/authentik/authentik.go | 284 ++++++++++++++++++++ pkg/provider/authentik/authentik_test.go | 319 +++++++++++++++++++++++ pkg/provider/authentik/model.go | 54 ++++ pkg/provider/authentik/model_test.go | 26 ++ saml2aws.go | 7 + 5 files changed, 690 insertions(+) create mode 100644 pkg/provider/authentik/authentik.go create mode 100644 pkg/provider/authentik/authentik_test.go create mode 100644 pkg/provider/authentik/model.go create mode 100644 pkg/provider/authentik/model_test.go diff --git a/pkg/provider/authentik/authentik.go b/pkg/provider/authentik/authentik.go new file mode 100644 index 000000000..ee8ae03c5 --- /dev/null +++ b/pkg/provider/authentik/authentik.go @@ -0,0 +1,284 @@ +package authentik + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/versent/saml2aws/v2/pkg/cfg" + "github.com/versent/saml2aws/v2/pkg/creds" + "github.com/versent/saml2aws/v2/pkg/provider" +) + +// Client wrapper around authentik. +type Client struct { + provider.ValidateBase + + client *provider.HTTPClient +} + +var logger = logrus.WithField("provider", "authentik") + +// New create a new client +func New(idpAccount *cfg.IDPAccount) (*Client, error) { + tr := provider.NewDefaultTransport(idpAccount.SkipVerify) + + client, err := provider.NewHTTPClient(tr, provider.BuildHttpClientOpts(idpAccount)) + if err != nil { + return nil, errors.Wrap(err, "error building http client") + } + + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + return &Client{ + client: client, + }, nil +} + +// Authenticate Log into authentik and returns a SAML response +func (kc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) { + ctx := &authentikContext{ + loginDetails: loginDetails, + } + samlResponse, err := kc.auth(ctx) + if err != nil { + return "", errors.Wrap(err, "error retrieving saml response from idp") + } + + return samlResponse, err +} + +// auth Authentication +func (kc *Client) auth(ctx *authentikContext) (string, error) { + logger.Debug("[GET] ", ctx.loginDetails.URL) + res, err := kc.client.Get(ctx.loginDetails.URL) + if err != nil { + return "", errors.Wrap(err, "error retrieving initial url") + } + if res.StatusCode == http.StatusFound { + var location *url.URL + location, err = res.Location() + if err != nil { + return "", err + } + err = ctx.updateURL(location.String()) + if err != nil { + return "", err + } + + return kc.auth(ctx) + } + + requestURL := res.Request.URL + if len(res.Cookies()) > 0 { + baseURL := &url.URL{Scheme: requestURL.Scheme, Host: requestURL.Host, Path: "/"} + kc.client.Jar.SetCookies(baseURL, res.Cookies()) + } + + next, err := kc.processQuery(ctx) + if err != nil { + return "", err + } + if ctx.samlResponse != "" { + return ctx.samlResponse, nil + } + + err = ctx.updateURL(next) + if err != nil { + return "", err + } + return kc.auth(ctx) +} + +// processQuery Loop to get the authentik credentials +func (kc *Client) processQuery(ctx *authentikContext) (string, error) { + var shouldContinue bool + var next string + var err error + + next, err = queryNextURL(ctx.loginDetails.URL) + if err != nil { + return "", err + } + err = ctx.updateURL(next) + if err != nil { + return "", err + } + + for { + shouldContinue, next, err = kc.queryNext(ctx) + if err != nil { + return "", err + } + if next != "" { + err = ctx.updateURL(next) + if err != nil { + return "", err + } + } + if !shouldContinue { + break + } + } + + return next, nil +} + +// queryNext Do query and submit infos +func (kc *Client) queryNext(ctx *authentikContext) (bool, string, error) { + logger.Debug("[GET] ", ctx.loginDetails.URL) + res, err := kc.client.Get(ctx.loginDetails.URL) + if err != nil { + return false, "", err + } + if res.StatusCode == http.StatusFound { + next, err1 := res.Location() + if err1 != nil { + return false, "", err1 + } + err = ctx.updateURL(next.String()) + if err != nil { + return false, "", err + } + + return kc.queryNext(ctx) + } + var payload *authentikPayload + payload, err = parseResponsePayload(res) + if err != nil { + return false, "", err + } + if payload.isTypeRedirect() { + // login success if there is a redirect + logger.Debug("Login success, redirect to saml response") + return false, payload.RedirectTo, nil + } else if !payload.isTypeNative() { + return false, "", errors.New("Unknown type: " + payload.Type) + } + + if payload.isComponentStageAutosubmit() { + ctx.setSAMLResponse(payload.Attrs["SAMLResponse"]) + return false, "", nil + } + + next, err := kc.doPostQuery(ctx, payload) + return true, next, err +} + +// doPostQuery For all data setting operations +func (kc *Client) doPostQuery(ctx *authentikContext, payload *authentikPayload) (string, error) { + data, err := getLoginJSON(ctx.loginDetails, payload) + if err != nil { + return "", err + } + + logger.Debug("[POST]", ctx.loginDetails.URL) + res, err := kc.client.Post(ctx.loginDetails.URL, "application/json", bytes.NewReader(data)) + if err != nil { + return "", err + } + if res.StatusCode == http.StatusOK { + var payload *authentikPayload + payload, err = parseResponsePayload(res) + if err != nil { + return "", err + } + + var errMsg string + if len(payload.Errors) > 0 { + errMsg = prepareErrors(payload.Component, payload.Errors) + } else { + errMsg = "Unexpected" + } + + return "", errors.New(errMsg) + } + loc, err := res.Location() + return loc.String(), err +} + +// getLoginJSON Generate the login json +func getLoginJSON(loginDetails *creds.LoginDetails, payload *authentikPayload) ([]byte, error) { + component := payload.Component + m := map[string]string{ + "component": component, + } + switch component { + case "ak-stage-identification": + m["uid_field"] = loginDetails.Username + if payload.HasPassowrdField { + m["password"] = loginDetails.Password + } + case "ak-stage-password": + m["password"] = loginDetails.Password + default: + return []byte(""), errors.New("unknown component: " + component) + } + + return json.Marshal(m) +} + +// queryNextURL Get the next api url +func queryNextURL(u string) (string, error) { + next, err := url.Parse(u) + if err != nil { + return "", errors.New("Invalid url") + } + + result := strings.Split(next.Path, "/") + flow := result[len(result)-2] + return fmt.Sprintf("%s://%s/api/v3/flows/executor/%s/?query=%s", next.Scheme, next.Host, flow, url.QueryEscape(next.RawQuery)), nil +} + +// getFieldName Get name of component +func getFieldName(component string) (string, error) { + prefix := "ak-stage-" + if strings.Index(component, prefix) != 0 { + return "", errors.New("") + } + s := strings.Split(component, "ak-stage-") + return s[len(s)-1], nil +} + +// prepareErrors Transform errors to string +func prepareErrors(component string, errs map[string][]map[string]string) string { + field, err := getFieldName(component) + if err != nil { + return "Invalid component" + } + + key := "non_field_errors" + if field == "password" { + key = "password" + } + msgs := make([]string, 0, len(errs[key])) + for _, err := range errs[key] { + msgs = append(msgs, fmt.Sprintf("%s %s: %s", field, err["code"], err["string"])) + } + return strings.Join(msgs, "; ") +} + +// parseResponsePayload Parse response from authentik api +func parseResponsePayload(res *http.Response) (*authentikPayload, error) { + var payload authentikPayload + defer res.Body.Close() + b, err := ioutil.ReadAll(res.Body) + err = json.Unmarshal(b, &payload) + if err != nil { + return nil, err + } + + return &payload, nil +} + +func aaa(a int) int { + return a + 1 +} diff --git a/pkg/provider/authentik/authentik_test.go b/pkg/provider/authentik/authentik_test.go new file mode 100644 index 000000000..3c38cefe9 --- /dev/null +++ b/pkg/provider/authentik/authentik_test.go @@ -0,0 +1,319 @@ +package authentik + +import ( + "testing" + + "github.com/h2non/gock" + "github.com/stretchr/testify/assert" + "github.com/versent/saml2aws/v2/pkg/cfg" + "github.com/versent/saml2aws/v2/pkg/creds" +) + +func Test_getLoginJSON(t *testing.T) { + assert := assert.New(t) + loginDetails := &creds.LoginDetails{ + Username: "user", + Password: "pwd", + URL: "https://127.0.0.1/sso/init", + } + payload := &authentikPayload{ + Component: "ak-stage-identification", + Type: "native", + } + b, err := getLoginJSON(loginDetails, payload) + assert.Nil(err) + assert.Equal(string(b), "{\"component\":\"ak-stage-identification\",\"uid_field\":\"user\"}") + + payload = &authentikPayload{ + Component: "ak-stage-password", + Type: "native", + } + b, err = getLoginJSON(loginDetails, payload) + assert.Nil(err) + assert.Equal(string(b), "{\"component\":\"ak-stage-password\",\"password\":\"pwd\"}") + + payload = &authentikPayload{ + Component: "ak-stage-test", + Type: "native", + } + b, err = getLoginJSON(loginDetails, payload) + assert.NotNil(err) +} + +func Test_queryNextURL(t *testing.T) { + assert := assert.New(t) + url, err := queryNextURL("https://127.0.0.1/if/flow/default-authentication-flow/?next=/application/saml/aws/sso/binding/init/") + assert.Nil(err) + assert.Equal(url, "https://127.0.0.1/api/v3/flows/executor/default-authentication-flow/?query=next%3D%2Fapplication%2Fsaml%2Faws%2Fsso%2Fbinding%2Finit%2F") +} + +func Test_getFieldName(t *testing.T) { + assert := assert.New(t) + var name string + var err error + name, err = getFieldName("ak-stage-identification") + assert.Nil(err) + assert.Equal(name, "identification") + + name, err = getFieldName("ak-stage-password") + assert.Nil(err) + assert.Equal(name, "password") + + name, err = getFieldName("ak-stage-") + assert.Nil(err) + assert.Equal(name, "") + + name, err = getFieldName("stage-password") + assert.NotNil(err) + assert.Equal(name, "") +} + +func Test_prepareErrors(t *testing.T) { + assert := assert.New(t) + var desc string + identification_errs := map[string][]map[string]string{ + "non_field_errors": { + { + "string": "Failed to authenticate.", + "code": "invalid", + }, + }, + } + desc = prepareErrors("ak-stage-identification", identification_errs) + assert.Equal(desc, "identification invalid: Failed to authenticate.") + + desc = prepareErrors("ak-stage-password", identification_errs) + assert.Equal(desc, "") + + password_errs := map[string][]map[string]string{ + "password": { + { + "string": "Failed to authenticate.", + "code": "invalid", + }, + }, + } + desc = prepareErrors("ak-stage-password", password_errs) + assert.Equal(desc, "password invalid: Failed to authenticate.") + + desc = prepareErrors("ak-stage-identification", password_errs) + assert.Equal(desc, "") +} + +// Test_authWithCombinedUsernamePassword Password only if username/email verified +func Test_authWithSeperatedUsernamePassword(t *testing.T) { + defer gock.Off() + samlResponse := "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaX" + gock.New("http://127.0.0.1"). + Get("/application/saml/aws/sso/binding/init"). + Reply(302). + SetHeader("Set-Cookie", "[authentik_session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWQiOiJ6cHI3NGdzMjNnOGNqbmF1bXNheGQ1dXVrc2VtZGZpNyIsImlzcyI6ImF1dGhlbnRpayIsInN1YiI6ImFub255bW91cyIsImF1dGhlbnRpY2F0ZWQiOmZhbHNlLCJhY3IiOiJnb2F1dGhlbnRpay5pby9jb3JlL2RlZmF1bHQifQ.zNiX4pk6G9ABeDip0PLs8-0irm2aQ_Arr_RgTxTGCQM; HttpOnly; Path=/; SameSite=None; Secure]"). + SetHeader("Location", "/flows/-/default/authentication/?next=/application/saml/aws/sso/binding/init/") + + gock.New("http://127.0.0.1"). + Get("/flows/-/default/authentication"). + Reply(302). + SetHeader("Location", "/if/flow/default-authentication-flow/?next=%2Fapplication%2Fsaml%2Faws%2Fsso%2Fbinding%2Finit%2F") + + gock.New("http://127.0.0.1"). + Get("/if/flow/default-authentication-flow"). + Reply(200). + BodyString("") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{"title": "Welcome to authentik!", "background": "/static/dist/assets/images/flow_background.jpg", "cancel_url": "/flows/-/cancel/", "layout": "stacked"}, + "component": "ak-stage-identification", + "user_fields": []string{"username", "email"}, + "password_fields": false, + "application_pre": "aws", + "primary_action": "Log in", + "sources": []string{}, + "show_source_labels": false, + }) + + gock.New("http://127.0.0.1"). + Post("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{"title": "Welcome to authentik!", "background": "/static/dist/assets/images/flow_background.jpg", "cancel_url": "/flows/-/cancel/", "layout": "stacked"}, + "component": "ak-stage-password", + "pending_user": "user", + "pending_user_avatar": "https://secure.gravatar.com/avatar/0932141298741243?s=158&r=g", + }) + gock.New("http://127.0.0.1"). + Post("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "redirect", + "to": "http://127.0.0.1/application/saml/aws/sso/binding/init", + }) + + gock.New("http://127.0.0.1"). + Get("/application/saml/aws/sso/binding/init"). + Reply(302). + SetHeader("Location", "/if/flow/default-provider-authorization-implicit-consent/") + + gock.New("http://127.0.0.1"). + Get("/if/flow/default-provider-authorization-implicit-consent/"). + Reply(200) + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{ + "title": "Redirecting to aws", + "background": "/static/dist/assets/images/flow_background.jpg", + "cancel_url": "/flows/-/cancel/", + "layout": "stacked", + }, + "component": "ak-stage-autosubmit", + "url": "https://signin.amazonaws.com/saml", + "attrs": map[string]interface{}{ + "ACSUrl": "https://signin.amazonaws.com/saml", + "SAMLResponse": samlResponse, + }, + }) + client, _ := New(&cfg.IDPAccount{}) + loginDetails := &creds.LoginDetails{ + Username: "user", + Password: "pwd", + URL: "http://127.0.0.1/application/saml/aws/sso/binding/init", + } + gock.InterceptClient(&client.client.Client) + result, err := client.Authenticate(loginDetails) + + assert := assert.New(t) + assert.Nil(err) + assert.Equal(result, samlResponse) +} + +// Test_authWithCombinedUsernamePassword Username/email and password in one page +func Test_authWithCombinedUsernamePassword(t *testing.T) { + defer gock.Off() + samlResponse := "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaX" + gock.New("http://127.0.0.1"). + Get("/application/saml/aws/sso/binding/init"). + Reply(302). + SetHeader("Set-Cookie", "[authentik_session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWQiOiJ6cHI3NGdzMjNnOGNqbmF1bXNheGQ1dXVrc2VtZGZpNyIsImlzcyI6ImF1dGhlbnRpayIsInN1YiI6ImFub255bW91cyIsImF1dGhlbnRpY2F0ZWQiOmZhbHNlLCJhY3IiOiJnb2F1dGhlbnRpay5pby9jb3JlL2RlZmF1bHQifQ.zNiX4pk6G9ABeDip0PLs8-0irm2aQ_Arr_RgTxTGCQM; HttpOnly; Path=/; SameSite=None; Secure]"). + SetHeader("Location", "/flows/-/default/authentication/?next=/application/saml/aws/sso/binding/init/") + + gock.New("http://127.0.0.1"). + Get("/flows/-/default/authentication"). + Reply(302). + SetHeader("Location", "/if/flow/default-authentication-flow/?next=%2Fapplication%2Fsaml%2Faws%2Fsso%2Fbinding%2Finit%2F") + + gock.New("http://127.0.0.1"). + Get("/if/flow/default-authentication-flow"). + Reply(200). + BodyString("") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{"title": "Welcome to authentik!", "background": "/static/dist/assets/images/flow_background.jpg", "cancel_url": "/flows/-/cancel/", "layout": "stacked"}, + "component": "ak-stage-identification", + "user_fields": []string{"username", "email"}, + "password_fields": true, + "application_pre": "aws", + "primary_action": "Log in", + "sources": []string{}, + "show_source_labels": false, + }) + + gock.New("http://127.0.0.1"). + Post("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{"title": "Welcome to authentik!", "background": "/static/dist/assets/images/flow_background.jpg", "cancel_url": "/flows/-/cancel/", "layout": "stacked"}, + "component": "ak-stage-password", + "pending_user": "user", + "pending_user_avatar": "https://secure.gravatar.com/avatar/0932141298741243?s=158&r=g", + }) + gock.New("http://127.0.0.1"). + Post("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(302). + SetHeader("Location", "/api/v3/flows/executor/default-authentication-flow/?query=next%3D%252F") + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows/executor/default-authentication-flow"). + Reply(200). + JSON(map[string]interface{}{ + "type": "redirect", + "to": "http://127.0.0.1/application/saml/aws/sso/binding/init", + }) + + gock.New("http://127.0.0.1"). + Get("/application/saml/aws/sso/binding/init"). + Reply(302). + SetHeader("Location", "/if/flow/default-provider-authorization-implicit-consent/") + + gock.New("http://127.0.0.1"). + Get("/if/flow/default-provider-authorization-implicit-consent/"). + Reply(200) + + gock.New("http://127.0.0.1"). + Get("/api/v3/flows"). + Reply(200). + JSON(map[string]interface{}{ + "type": "native", + "flow_info": map[string]interface{}{ + "title": "Redirecting to aws", + "background": "/static/dist/assets/images/flow_background.jpg", + "cancel_url": "/flows/-/cancel/", + "layout": "stacked", + }, + "component": "ak-stage-autosubmit", + "url": "https://signin.amazonaws.com/saml", + "attrs": map[string]interface{}{ + "ACSUrl": "https://signin.amazonaws.com/saml", + "SAMLResponse": samlResponse, + }, + }) + client, _ := New(&cfg.IDPAccount{}) + loginDetails := &creds.LoginDetails{ + Username: "user", + Password: "pwd", + URL: "http://127.0.0.1/application/saml/aws/sso/binding/init", + } + gock.InterceptClient(&client.client.Client) + result, err := client.Authenticate(loginDetails) + + assert := assert.New(t) + assert.Nil(err) + assert.Equal(result, samlResponse) +} diff --git a/pkg/provider/authentik/model.go b/pkg/provider/authentik/model.go new file mode 100644 index 000000000..1bffe7d9f --- /dev/null +++ b/pkg/provider/authentik/model.go @@ -0,0 +1,54 @@ +package authentik + +import ( + "fmt" + "net/url" + "strings" + + "github.com/pkg/errors" + + "github.com/versent/saml2aws/v2/pkg/creds" +) + +type authentikContext struct { + loginDetails *creds.LoginDetails + samlResponse string +} + +type authentikPayload struct { + Attrs map[string]string + Component string + Type string + HasPassowrdField bool `json:"password_fields"` + RedirectTo string `json:"to"` + Errors map[string][]map[string]string `json:"response_errors"` +} + +func (ctx *authentikContext) updateURL(s string) error { + if strings.Index(s, "/") == 0 { + u, err := url.Parse(ctx.loginDetails.URL) + if err != nil { + return errors.New("Invalid url") + } + s = fmt.Sprintf("%s://%s%s", u.Scheme, u.Host, s) + } + + ctx.loginDetails.URL = s + return nil +} + +func (ctx *authentikContext) setSAMLResponse(val string) { + ctx.samlResponse = val +} + +func (payload *authentikPayload) isTypeNative() bool { + return payload.Type == "native" +} + +func (payload *authentikPayload) isTypeRedirect() bool { + return payload.Type == "redirect" +} + +func (payload *authentikPayload) isComponentStageAutosubmit() bool { + return payload.Component == "ak-stage-autosubmit" +} diff --git a/pkg/provider/authentik/model_test.go b/pkg/provider/authentik/model_test.go new file mode 100644 index 000000000..62df451fd --- /dev/null +++ b/pkg/provider/authentik/model_test.go @@ -0,0 +1,26 @@ +package authentik + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/versent/saml2aws/v2/pkg/creds" +) + +func Test_updateURL(t *testing.T) { + assert := assert.New(t) + ctx := &authentikContext{ + loginDetails: &creds.LoginDetails{ + Username: "user", + Password: "pwd", + URL: "https://127.0.0.1/sso/init", + }, + } + err := ctx.updateURL("/query?next=/login") + assert.Nil(err) + assert.Equal(ctx.loginDetails.URL, "https://127.0.0.1/query?next=/login") + + err = ctx.updateURL("https://127.0.0.1:8888/sso/aws") + assert.Nil(err) + assert.Equal(ctx.loginDetails.URL, "https://127.0.0.1:8888/sso/aws") +} diff --git a/saml2aws.go b/saml2aws.go index 678085380..914cf78c7 100644 --- a/saml2aws.go +++ b/saml2aws.go @@ -11,6 +11,7 @@ import ( "github.com/versent/saml2aws/v2/pkg/provider/adfs2" "github.com/versent/saml2aws/v2/pkg/provider/akamai" "github.com/versent/saml2aws/v2/pkg/provider/auth0" + "github.com/versent/saml2aws/v2/pkg/provider/authentik" "github.com/versent/saml2aws/v2/pkg/provider/browser" "github.com/versent/saml2aws/v2/pkg/provider/f5apm" "github.com/versent/saml2aws/v2/pkg/provider/googleapps" @@ -39,6 +40,7 @@ var MFAsByProvider = ProviderList{ "JumpCloud": []string{"Auto", "TOTP", "WEBAUTHN", "DUO", "PUSH"}, "Okta": []string{"Auto", "PUSH", "DUO", "SMS", "TOTP", "OKTA", "FIDO", "YUBICO TOKEN:HARDWARE", "SYMANTEC"}, // automatically detects DUO, SMS, ToTP, and FIDO "OneLogin": []string{"Auto", "OLP", "SMS", "TOTP", "YUBIKEY"}, // automatically detects OneLogin Protect, SMS and ToTP + "Authentik": []string{"Auto"}, "KeyCloak": []string{"Auto"}, // automatically detects ToTP "GoogleApps": []string{"Auto"}, // automatically detects ToTP "Shibboleth": []string{"Auto", "None"}, @@ -134,6 +136,11 @@ func NewSAMLClient(idpAccount *cfg.IDPAccount) (SAMLClient, error) { return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider) } return onelogin.New(idpAccount) + case "Authentik": + if invalidMFA(idpAccount.Provider, idpAccount.MFA) { + return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider) + } + return authentik.New(idpAccount) case "KeyCloak": if invalidMFA(idpAccount.Provider, idpAccount.MFA) { return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider) From fcb2b2515ef256a041e6c061ce807899ef576a0a Mon Sep 17 00:00:00 2001 From: Hunter Date: Tue, 14 Mar 2023 00:17:23 +0000 Subject: [PATCH 37/54] fix: authentik test --- go.mod | 2 ++ go.sum | 5 +++++ pkg/provider/authentik/authentik_test.go | 9 +++++---- saml2aws_test.go | 6 +----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index ac1b7be82..e9b475323 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,8 @@ require ( github.com/go-stack/stack v1.8.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/h2non/gock v1.2.0 // indirect + github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-colorable v0.1.2 // indirect diff --git a/go.sum b/go.sum index d1073b3be..9d5148969 100644 --- a/go.sum +++ b/go.sum @@ -82,6 +82,10 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= +github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= @@ -121,6 +125,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= diff --git a/pkg/provider/authentik/authentik_test.go b/pkg/provider/authentik/authentik_test.go index 3c38cefe9..78c15c249 100644 --- a/pkg/provider/authentik/authentik_test.go +++ b/pkg/provider/authentik/authentik_test.go @@ -5,6 +5,7 @@ import ( "github.com/h2non/gock" "github.com/stretchr/testify/assert" + "github.com/versent/saml2aws/v2/pkg/cfg" "github.com/versent/saml2aws/v2/pkg/creds" ) @@ -36,7 +37,7 @@ func Test_getLoginJSON(t *testing.T) { Component: "ak-stage-test", Type: "native", } - b, err = getLoginJSON(loginDetails, payload) + _, err = getLoginJSON(loginDetails, payload) assert.NotNil(err) } @@ -85,7 +86,7 @@ func Test_prepareErrors(t *testing.T) { desc = prepareErrors("ak-stage-password", identification_errs) assert.Equal(desc, "") - password_errs := map[string][]map[string]string{ + passwordErrs := map[string][]map[string]string{ "password": { { "string": "Failed to authenticate.", @@ -93,10 +94,10 @@ func Test_prepareErrors(t *testing.T) { }, }, } - desc = prepareErrors("ak-stage-password", password_errs) + desc = prepareErrors("ak-stage-password", passwordErrs) assert.Equal(desc, "password invalid: Failed to authenticate.") - desc = prepareErrors("ak-stage-identification", password_errs) + desc = prepareErrors("ak-stage-identification", passwordErrs) assert.Equal(desc, "") } diff --git a/saml2aws_test.go b/saml2aws_test.go index 51e0955c4..d87e4a52e 100644 --- a/saml2aws_test.go +++ b/saml2aws_test.go @@ -7,17 +7,13 @@ import ( ) func TestProviderList_Keys(t *testing.T) { - names := MFAsByProvider.Names() - require.Len(t, names, 17) - + require.Len(t, names, 18) } func TestProviderList_Mfas(t *testing.T) { - mfas := MFAsByProvider.Mfas("Ping") require.Len(t, mfas, 1) - } From 755dbed51613fd6537f8f024436e20dc79d2f67d Mon Sep 17 00:00:00 2001 From: Hunter Date: Tue, 14 Mar 2023 05:55:37 +0000 Subject: [PATCH 38/54] fix: remove unused function --- pkg/provider/authentik/authentik.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/provider/authentik/authentik.go b/pkg/provider/authentik/authentik.go index ee8ae03c5..e7cb49d5c 100644 --- a/pkg/provider/authentik/authentik.go +++ b/pkg/provider/authentik/authentik.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -270,7 +270,10 @@ func prepareErrors(component string, errs map[string][]map[string]string) string func parseResponsePayload(res *http.Response) (*authentikPayload, error) { var payload authentikPayload defer res.Body.Close() - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } err = json.Unmarshal(b, &payload) if err != nil { return nil, err @@ -278,7 +281,3 @@ func parseResponsePayload(res *http.Response) (*authentikPayload, error) { return &payload, nil } - -func aaa(a int) int { - return a + 1 -} From 3ba897037fa788c96aad255c9da417694b8d055f Mon Sep 17 00:00:00 2001 From: Hunter Date: Tue, 14 Mar 2023 09:18:47 +0000 Subject: [PATCH 39/54] chore: format --- saml2aws.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/saml2aws.go b/saml2aws.go index 914cf78c7..fa10a6c5f 100644 --- a/saml2aws.go +++ b/saml2aws.go @@ -41,8 +41,8 @@ var MFAsByProvider = ProviderList{ "Okta": []string{"Auto", "PUSH", "DUO", "SMS", "TOTP", "OKTA", "FIDO", "YUBICO TOKEN:HARDWARE", "SYMANTEC"}, // automatically detects DUO, SMS, ToTP, and FIDO "OneLogin": []string{"Auto", "OLP", "SMS", "TOTP", "YUBIKEY"}, // automatically detects OneLogin Protect, SMS and ToTP "Authentik": []string{"Auto"}, - "KeyCloak": []string{"Auto"}, // automatically detects ToTP - "GoogleApps": []string{"Auto"}, // automatically detects ToTP + "KeyCloak": []string{"Auto"}, // automatically detects ToTP + "GoogleApps": []string{"Auto"}, // automatically detects ToTP "Shibboleth": []string{"Auto", "None"}, "F5APM": []string{"Auto"}, "Akamai": []string{"Auto", "DUO", "SMS", "EMAIL", "TOTP"}, From 8985ca5cbf3ec425088bc5c35fafb7a692853233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Wed, 15 Mar 2023 20:09:05 -0400 Subject: [PATCH 40/54] Add Codecov to GHA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .github/workflows/go.yml | 8 +++++- README.md | 55 +++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 16a89177e..bab531b7e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,7 +25,13 @@ jobs: uses: actions/checkout@v3 - name: Test - run: go test -v ./... + run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic + + - name: Codecov + uses: codecov/codecov-action@v3 + with: + file: coverage.txt + flags: unittests - name: Install run: go install ./cmd/saml2aws diff --git a/README.md b/README.md index c738da22a..4a66018f6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# saml2aws [![GitHub Actions status](https://github.com/Versent/saml2aws/workflows/Go/badge.svg?branch=master)](https://github.com/Versent/saml2aws/actions?query=workflow%3AGo) [![Build status - Windows](https://ci.appveyor.com/api/projects/status/ptpi18kci16o4i82/branch/master?svg=true)](https://ci.appveyor.com/project/davidobrien1985/saml2aws/branch/master) +# saml2aws + +[![GitHub Actions status](https://github.com/Versent/saml2aws/workflows/Go/badge.svg?branch=master)](https://github.com/Versent/saml2aws/actions?query=workflow%3AGo) [![Build status - Windows](https://ci.appveyor.com/api/projects/status/ptpi18kci16o4i82/branch/master?svg=true)](https://ci.appveyor.com/project/davidobrien1985/saml2aws/branch/master) +[![codecov](https://codecov.io/github/Versent/saml2aws/branch/master/graph/badge.svg)](https://codecov.io/github/Versent/saml2aws) CLI tool which enables you to login and retrieve [AWS](https://aws.amazon.com/) temporary credentials using with [ADFS](https://msdn.microsoft.com/en-us/library/bb897402.aspx) or [PingFederate](https://www.pingidentity.com/en/products/pingfederate.html) Identity Providers. @@ -18,25 +21,47 @@ The process goes something like this: ## Table of Contents -- [Table of Contents](#table-of-contents) -- [Requirements](#requirements) -- [Caveats](#caveats) -- [Install](#install) +- [saml2aws](#saml2aws) + - [Table of Contents](#table-of-contents) + - [Requirements](#requirements) + - [Caveats](#caveats) + - [Install](#install) - [OSX](#osx) - [Windows](#windows) - [Linux](#linux) -- [Autocomplete](#autocomplete) -- [Dependency Setup](#dependency-setup) -- [Usage](#usage) + - [Using Make](#using-make) + - [Arch Linux and its derivatives](#arch-linux-and-its-derivatives) + - [Void Linux](#void-linux) + - [Autocomplete](#autocomplete) + - [Bash](#bash) + - [Zsh](#zsh) + - [Dependency Setup](#dependency-setup) + - [Usage](#usage) - [`saml2aws script`](#saml2aws-script) + - [`saml2aws exec`](#saml2aws-exec) - [Configuring IDP Accounts](#configuring-idp-accounts) -- [Example](#example) -- [Advanced Configuration](#advanced-configuration) - - [Dev Account Setup](#dev-account-setup) - - [Test Account Setup](#test-account-setup) -- [Building](#building) -- [Environment vars](#environment-vars) -- [Provider Specific Documentation](#provider-specific-documentation) + - [Example](#example) + - [Advanced Configuration](#advanced-configuration) + - [Windows Subsystem Linux (WSL) Configuration](#windows-subsystem-linux-wsl-configuration) + - [Option 1: Disable Keychain](#option-1-disable-keychain) + - [Option 2: Configure Pass to be the default keyring](#option-2-configure-pass-to-be-the-default-keyring) + - [Configuring Multiple Accounts](#configuring-multiple-accounts) + - [Dev Account Setup](#dev-account-setup) + - [Test Account Setup](#test-account-setup) + - [Advanced Configuration (Multiple AWS account access but SAML authenticate against a single 'SSO' AWS account)](#advanced-configuration-multiple-aws-account-access-but-saml-authenticate-against-a-single-sso-aws-account) + - [Advanced Configuration - additional parameters](#advanced-configuration---additional-parameters) + - [Building](#building) + - [macOS](#macos) + - [Linux](#linux-1) + - [Environment vars](#environment-vars) + - [Provider Specific Documentation](#provider-specific-documentation) +- [Dependencies](#dependencies) +- [Releasing](#releasing) +- [Debugging Issues with IDPs](#debugging-issues-with-idps) +- [Using saml2aws as credential process](#using-saml2aws-as-credential-process) +- [Caching the saml2aws SAML assertion for immediate reuse](#caching-the-saml2aws-saml-assertion-for-immediate-reuse) +- [Okta Sessions](#okta-sessions) +- [License](#license) ## Requirements From d24a0ffa983637579b4cbf9393436241f8a592cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Thu, 16 Mar 2023 20:41:08 -0400 Subject: [PATCH 41/54] Correct Codecov badge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a66018f6..b4e98f769 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # saml2aws [![GitHub Actions status](https://github.com/Versent/saml2aws/workflows/Go/badge.svg?branch=master)](https://github.com/Versent/saml2aws/actions?query=workflow%3AGo) [![Build status - Windows](https://ci.appveyor.com/api/projects/status/ptpi18kci16o4i82/branch/master?svg=true)](https://ci.appveyor.com/project/davidobrien1985/saml2aws/branch/master) -[![codecov](https://codecov.io/github/Versent/saml2aws/branch/master/graph/badge.svg)](https://codecov.io/github/Versent/saml2aws) +[![codecov](https://codecov.io/gh/Versent/saml2aws/branch/master/graph/badge.svg)](https://codecov.io/gh/Versent/saml2aws) CLI tool which enables you to login and retrieve [AWS](https://aws.amazon.com/) temporary credentials using with [ADFS](https://msdn.microsoft.com/en-us/library/bb897402.aspx) or [PingFederate](https://www.pingidentity.com/en/products/pingfederate.html) Identity Providers. From bdab1ecf32e732eb4589d7f44e928021640809a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Thu, 16 Mar 2023 20:57:21 -0400 Subject: [PATCH 42/54] Add to saml.go tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- saml_test.go | 33 +++++++++++++++++++++++++++++++++ testdata/notxml.xml | 1 + 2 files changed, 34 insertions(+) create mode 100644 testdata/notxml.xml diff --git a/saml_test.go b/saml_test.go index 5118c5bd7..38338dcfb 100644 --- a/saml_test.go +++ b/saml_test.go @@ -17,6 +17,14 @@ func TestExtractAwsRoles(t *testing.T) { assert.Len(t, roles, 2) } +func TestExtractAwsRolesFail(t *testing.T) { + data, err := os.ReadFile("testdata/notxml.xml") + assert.Nil(t, err) + + _, err = ExtractAwsRoles(data) + assert.Error(t, err) +} + func TestExtractSessionDuration(t *testing.T) { data, err := os.ReadFile("testdata/assertion.xml") assert.Nil(t, err) @@ -26,6 +34,14 @@ func TestExtractSessionDuration(t *testing.T) { assert.Equal(t, int64(28800), duration) } +func TestExtractSessionDurationFail(t *testing.T) { + data, err := os.ReadFile("testdata/notxml.xml") + assert.Nil(t, err) + + _, err = ExtractSessionDuration(data) + assert.Error(t, err) +} + func TestExtractDestinationURL(t *testing.T) { data, err := os.ReadFile("testdata/assertion.xml") assert.Nil(t, err) @@ -35,6 +51,14 @@ func TestExtractDestinationURL(t *testing.T) { assert.Equal(t, "https://signin.aws.amazon.com/saml", destination) } +func TestExtractDestinationURLFail(t *testing.T) { + data, err := os.ReadFile("testdata/notxml.xml") + assert.Nil(t, err) + + _, err = ExtractDestinationURL(data) + assert.Error(t, err) +} + func TestExtractDestinationURL2(t *testing.T) { data, err := os.ReadFile("testdata/assertion_no_destination.xml") assert.Nil(t, err) @@ -54,6 +78,15 @@ func TestExtractMFATokenDuration(t *testing.T) { assert.Equal(t, "2016-09-10T02:59:39Z", timeObject.Format(time.RFC3339)) } +func TestExtractMFATokenDurationFail(t *testing.T) { + data, err := os.ReadFile("testdata/notxml.xml") + assert.Nil(t, err) + + _, err = ExtractMFATokenExpiryTime(data) + + assert.Error(t, err) +} + func TestExtractMFATokenDuration2(t *testing.T) { data, err := os.ReadFile("testdata/assertion_invalid_date.xml") assert.Nil(t, err) diff --git a/testdata/notxml.xml b/testdata/notxml.xml new file mode 100644 index 000000000..66c441f4e --- /dev/null +++ b/testdata/notxml.xml @@ -0,0 +1 @@ +??? \ No newline at end of file From 2ee43714f961abc762927c95a261f9a8504671be Mon Sep 17 00:00:00 2001 From: Christian Meyer Date: Fri, 17 Mar 2023 15:26:06 +0100 Subject: [PATCH 43/54] fix typo introduced by prior merge --- pkg/provider/aad/aad_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/provider/aad/aad_test.go b/pkg/provider/aad/aad_test.go index 9294fe8db..76a1ca965 100644 --- a/pkg/provider/aad/aad_test.go +++ b/pkg/provider/aad/aad_test.go @@ -459,7 +459,7 @@ func genIntFixture(length int) string { func genUUID() string { return uuid.New().String() -) +} func TestAad_UnmarshallMfaResponseWithEntropy(t *testing.T) { From f634434aa4263042396157a7ee016f023bd8ba0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 17 Mar 2023 19:16:44 -0400 Subject: [PATCH 44/54] Ignore coverage.xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .gitignore | 1 + coverage.xml | 11135 ------------------------------------------------- 2 files changed, 1 insertion(+), 11135 deletions(-) delete mode 100644 coverage.xml diff --git a/.gitignore b/.gitignore index 186524f9f..3df4ff757 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ vendor /package /stage coverage.txt +coverage.xml .ctags .vscode bin/ diff --git a/coverage.xml b/coverage.xml deleted file mode 100644 index 3f52527f0..000000000 --- a/coverage.xml +++ /dev/null @@ -1,11135 +0,0 @@ - - - - - /home/markw/Code/notgopath/saml2aws - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From ce5b263e899753b94721041f0d47c3b7323f46db Mon Sep 17 00:00:00 2001 From: Nick Lopez <20211302+nlopez@users.noreply.github.com> Date: Tue, 17 Jan 2023 16:32:49 -0500 Subject: [PATCH 45/54] support different aws saml signin URLs for browser method --- pkg/provider/browser/browser.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/provider/browser/browser.go b/pkg/provider/browser/browser.go index ff31cf75e..32a8e687e 100644 --- a/pkg/provider/browser/browser.go +++ b/pkg/provider/browser/browser.go @@ -3,6 +3,7 @@ package browser import ( "errors" "net/url" + "regexp" "github.com/playwright-community/playwright-go" "github.com/sirupsen/logrus" @@ -52,7 +53,15 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) return "", err } - r := page.WaitForRequest("https://signin.aws.amazon.com/saml") + // https://docs.aws.amazon.com/general/latest/gr/signin-service.html + // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Ningxia.html + // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Beijing.html + signin_re, err := regexp.Compile(`https:\/\/((.*\.)?signin\.(aws\.amazon\.com|amazonaws-us-gov\.com|amazonaws\.cn))\/saml`) + if err != nil { + return "", err + } + + r := page.WaitForRequest(signin_re) data, err := r.PostData() if err != nil { return "", err From 8d98e5a37ce359a5ee8a174d793e7fd904460a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lipt=C3=A1k?= Date: Fri, 17 Mar 2023 19:19:26 -0400 Subject: [PATCH 46/54] Add browser test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Lipták --- .github/workflows/go.yml | 7 +- mocks/Page.go | 2132 ++++++++++++++++++++++++++ mocks/Request.go | 398 +++++ pkg/cfg/cfg.go | 1 + pkg/provider/browser/browser.go | 39 +- pkg/provider/browser/browser_test.go | 43 + 6 files changed, 2606 insertions(+), 14 deletions(-) create mode 100644 mocks/Page.go create mode 100644 mocks/Request.go create mode 100644 pkg/provider/browser/browser_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index bab531b7e..3ca625fee 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macOS-latest, macos-11] + os: [ubuntu-18.04, macOS-latest, macos-11] steps: - name: Set up Go 1.x @@ -25,7 +25,10 @@ jobs: uses: actions/checkout@v3 - name: Test - run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic + run: | + go install github.com/playwright-community/playwright-go/cmd/playwright + playwright install --with-deps + go test -v ./... -coverprofile=coverage.txt -covermode=atomic - name: Codecov uses: codecov/codecov-action@v3 diff --git a/mocks/Page.go b/mocks/Page.go new file mode 100644 index 000000000..ec462e96a --- /dev/null +++ b/mocks/Page.go @@ -0,0 +1,2132 @@ +// Code generated by mockery v2.22.1. DO NOT EDIT. + +package mocks + +import ( + playwright "github.com/playwright-community/playwright-go" + mock "github.com/stretchr/testify/mock" +) + +// Page is an autogenerated mock type for the Page type +type Page struct { + mock.Mock +} + +// AddInitScript provides a mock function with given fields: script +func (_m *Page) AddInitScript(script playwright.PageAddInitScriptOptions) error { + ret := _m.Called(script) + + var r0 error + if rf, ok := ret.Get(0).(func(playwright.PageAddInitScriptOptions) error); ok { + r0 = rf(script) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AddScriptTag provides a mock function with given fields: options +func (_m *Page) AddScriptTag(options playwright.PageAddScriptTagOptions) (playwright.ElementHandle, error) { + ret := _m.Called(options) + + var r0 playwright.ElementHandle + var r1 error + if rf, ok := ret.Get(0).(func(playwright.PageAddScriptTagOptions) (playwright.ElementHandle, error)); ok { + return rf(options) + } + if rf, ok := ret.Get(0).(func(playwright.PageAddScriptTagOptions) playwright.ElementHandle); ok { + r0 = rf(options) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.ElementHandle) + } + } + + if rf, ok := ret.Get(1).(func(playwright.PageAddScriptTagOptions) error); ok { + r1 = rf(options) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AddStyleTag provides a mock function with given fields: options +func (_m *Page) AddStyleTag(options playwright.PageAddStyleTagOptions) (playwright.ElementHandle, error) { + ret := _m.Called(options) + + var r0 playwright.ElementHandle + var r1 error + if rf, ok := ret.Get(0).(func(playwright.PageAddStyleTagOptions) (playwright.ElementHandle, error)); ok { + return rf(options) + } + if rf, ok := ret.Get(0).(func(playwright.PageAddStyleTagOptions) playwright.ElementHandle); ok { + r0 = rf(options) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.ElementHandle) + } + } + + if rf, ok := ret.Get(1).(func(playwright.PageAddStyleTagOptions) error); ok { + r1 = rf(options) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BringToFront provides a mock function with given fields: +func (_m *Page) BringToFront() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Check provides a mock function with given fields: selector, options +func (_m *Page) Check(selector string, options ...playwright.FrameCheckOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameCheckOptions) error); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Click provides a mock function with given fields: selector, options +func (_m *Page) Click(selector string, options ...playwright.PageClickOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageClickOptions) error); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Close provides a mock function with given fields: options +func (_m *Page) Close(options ...playwright.PageCloseOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(...playwright.PageCloseOptions) error); ok { + r0 = rf(options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Content provides a mock function with given fields: +func (_m *Page) Content() (string, error) { + ret := _m.Called() + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Context provides a mock function with given fields: +func (_m *Page) Context() playwright.BrowserContext { + ret := _m.Called() + + var r0 playwright.BrowserContext + if rf, ok := ret.Get(0).(func() playwright.BrowserContext); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.BrowserContext) + } + } + + return r0 +} + +// Dblclick provides a mock function with given fields: expression, options +func (_m *Page) Dblclick(expression string, options ...playwright.FrameDblclickOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, expression) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameDblclickOptions) error); ok { + r0 = rf(expression, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DispatchEvent provides a mock function with given fields: selector, typ, options +func (_m *Page) DispatchEvent(selector string, typ string, options ...playwright.PageDispatchEventOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, typ) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.PageDispatchEventOptions) error); ok { + r0 = rf(selector, typ, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DragAndDrop provides a mock function with given fields: source, target, options +func (_m *Page) DragAndDrop(source string, target string, options ...playwright.FrameDragAndDropOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, source, target) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.FrameDragAndDropOptions) error); ok { + r0 = rf(source, target, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Emit provides a mock function with given fields: name, payload +func (_m *Page) Emit(name string, payload ...interface{}) { + var _ca []interface{} + _ca = append(_ca, name) + _ca = append(_ca, payload...) + _m.Called(_ca...) +} + +// EmulateMedia provides a mock function with given fields: options +func (_m *Page) EmulateMedia(options ...playwright.PageEmulateMediaOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(...playwright.PageEmulateMediaOptions) error); ok { + r0 = rf(options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EvalOnSelector provides a mock function with given fields: selector, expression, options +func (_m *Page) EvalOnSelector(selector string, expression string, options ...interface{}) (interface{}, error) { + var _ca []interface{} + _ca = append(_ca, selector, expression) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, string, ...interface{}) (interface{}, error)); ok { + return rf(selector, expression, options...) + } + if rf, ok := ret.Get(0).(func(string, string, ...interface{}) interface{}); ok { + r0 = rf(selector, expression, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, string, ...interface{}) error); ok { + r1 = rf(selector, expression, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EvalOnSelectorAll provides a mock function with given fields: selector, expression, options +func (_m *Page) EvalOnSelectorAll(selector string, expression string, options ...interface{}) (interface{}, error) { + var _ca []interface{} + _ca = append(_ca, selector, expression) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, string, ...interface{}) (interface{}, error)); ok { + return rf(selector, expression, options...) + } + if rf, ok := ret.Get(0).(func(string, string, ...interface{}) interface{}); ok { + r0 = rf(selector, expression, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, string, ...interface{}) error); ok { + r1 = rf(selector, expression, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Evaluate provides a mock function with given fields: expression, options +func (_m *Page) Evaluate(expression string, options ...interface{}) (interface{}, error) { + var _ca []interface{} + _ca = append(_ca, expression) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, ...interface{}) (interface{}, error)); ok { + return rf(expression, options...) + } + if rf, ok := ret.Get(0).(func(string, ...interface{}) interface{}); ok { + r0 = rf(expression, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, ...interface{}) error); ok { + r1 = rf(expression, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EvaluateHandle provides a mock function with given fields: expression, options +func (_m *Page) EvaluateHandle(expression string, options ...interface{}) (playwright.JSHandle, error) { + var _ca []interface{} + _ca = append(_ca, expression) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 playwright.JSHandle + var r1 error + if rf, ok := ret.Get(0).(func(string, ...interface{}) (playwright.JSHandle, error)); ok { + return rf(expression, options...) + } + if rf, ok := ret.Get(0).(func(string, ...interface{}) playwright.JSHandle); ok { + r0 = rf(expression, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.JSHandle) + } + } + + if rf, ok := ret.Get(1).(func(string, ...interface{}) error); ok { + r1 = rf(expression, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectConsoleMessage provides a mock function with given fields: cb +func (_m *Page) ExpectConsoleMessage(cb func() error) (playwright.ConsoleMessage, error) { + ret := _m.Called(cb) + + var r0 playwright.ConsoleMessage + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.ConsoleMessage, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.ConsoleMessage); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.ConsoleMessage) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectDownload provides a mock function with given fields: cb +func (_m *Page) ExpectDownload(cb func() error) (playwright.Download, error) { + ret := _m.Called(cb) + + var r0 playwright.Download + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.Download, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.Download); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Download) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectEvent provides a mock function with given fields: event, cb, predicates +func (_m *Page) ExpectEvent(event string, cb func() error, predicates ...interface{}) (interface{}, error) { + var _ca []interface{} + _ca = append(_ca, event, cb) + _ca = append(_ca, predicates...) + ret := _m.Called(_ca...) + + var r0 interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, func() error, ...interface{}) (interface{}, error)); ok { + return rf(event, cb, predicates...) + } + if rf, ok := ret.Get(0).(func(string, func() error, ...interface{}) interface{}); ok { + r0 = rf(event, cb, predicates...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, func() error, ...interface{}) error); ok { + r1 = rf(event, cb, predicates...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectFileChooser provides a mock function with given fields: cb +func (_m *Page) ExpectFileChooser(cb func() error) (playwright.FileChooser, error) { + ret := _m.Called(cb) + + var r0 playwright.FileChooser + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.FileChooser, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.FileChooser); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.FileChooser) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectLoadState provides a mock function with given fields: state, cb +func (_m *Page) ExpectLoadState(state string, cb func() error) error { + ret := _m.Called(state, cb) + + var r0 error + if rf, ok := ret.Get(0).(func(string, func() error) error); ok { + r0 = rf(state, cb) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ExpectNavigation provides a mock function with given fields: cb, options +func (_m *Page) ExpectNavigation(cb func() error, options ...playwright.PageWaitForNavigationOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, cb) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(func() error, ...playwright.PageWaitForNavigationOptions) (playwright.Response, error)); ok { + return rf(cb, options...) + } + if rf, ok := ret.Get(0).(func(func() error, ...playwright.PageWaitForNavigationOptions) playwright.Response); ok { + r0 = rf(cb, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(func() error, ...playwright.PageWaitForNavigationOptions) error); ok { + r1 = rf(cb, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectPopup provides a mock function with given fields: cb +func (_m *Page) ExpectPopup(cb func() error) (playwright.Page, error) { + ret := _m.Called(cb) + + var r0 playwright.Page + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.Page, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.Page); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Page) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectRequest provides a mock function with given fields: url, cb, options +func (_m *Page) ExpectRequest(url interface{}, cb func() error, options ...interface{}) (playwright.Request, error) { + var _ca []interface{} + _ca = append(_ca, url, cb) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 playwright.Request + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, func() error, ...interface{}) (playwright.Request, error)); ok { + return rf(url, cb, options...) + } + if rf, ok := ret.Get(0).(func(interface{}, func() error, ...interface{}) playwright.Request); ok { + r0 = rf(url, cb, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Request) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, func() error, ...interface{}) error); ok { + r1 = rf(url, cb, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectResponse provides a mock function with given fields: url, cb, options +func (_m *Page) ExpectResponse(url interface{}, cb func() error, options ...interface{}) (playwright.Response, error) { + var _ca []interface{} + _ca = append(_ca, url, cb) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, func() error, ...interface{}) (playwright.Response, error)); ok { + return rf(url, cb, options...) + } + if rf, ok := ret.Get(0).(func(interface{}, func() error, ...interface{}) playwright.Response); ok { + r0 = rf(url, cb, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, func() error, ...interface{}) error); ok { + r1 = rf(url, cb, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectWorker provides a mock function with given fields: cb +func (_m *Page) ExpectWorker(cb func() error) (playwright.Worker, error) { + ret := _m.Called(cb) + + var r0 playwright.Worker + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.Worker, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.Worker); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Worker) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExpectedDialog provides a mock function with given fields: cb +func (_m *Page) ExpectedDialog(cb func() error) (playwright.Dialog, error) { + ret := _m.Called(cb) + + var r0 playwright.Dialog + var r1 error + if rf, ok := ret.Get(0).(func(func() error) (playwright.Dialog, error)); ok { + return rf(cb) + } + if rf, ok := ret.Get(0).(func(func() error) playwright.Dialog); ok { + r0 = rf(cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Dialog) + } + } + + if rf, ok := ret.Get(1).(func(func() error) error); ok { + r1 = rf(cb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExposeBinding provides a mock function with given fields: name, binding, handle +func (_m *Page) ExposeBinding(name string, binding playwright.BindingCallFunction, handle ...bool) error { + _va := make([]interface{}, len(handle)) + for _i := range handle { + _va[_i] = handle[_i] + } + var _ca []interface{} + _ca = append(_ca, name, binding) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, playwright.BindingCallFunction, ...bool) error); ok { + r0 = rf(name, binding, handle...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ExposeFunction provides a mock function with given fields: name, binding +func (_m *Page) ExposeFunction(name string, binding func([]interface{}) interface{}) error { + ret := _m.Called(name, binding) + + var r0 error + if rf, ok := ret.Get(0).(func(string, func([]interface{}) interface{}) error); ok { + r0 = rf(name, binding) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Fill provides a mock function with given fields: selector, text, options +func (_m *Page) Fill(selector string, text string, options ...playwright.FrameFillOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, text) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.FrameFillOptions) error); ok { + r0 = rf(selector, text, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Focus provides a mock function with given fields: expression, options +func (_m *Page) Focus(expression string, options ...playwright.FrameFocusOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, expression) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameFocusOptions) error); ok { + r0 = rf(expression, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Frame provides a mock function with given fields: options +func (_m *Page) Frame(options playwright.PageFrameOptions) playwright.Frame { + ret := _m.Called(options) + + var r0 playwright.Frame + if rf, ok := ret.Get(0).(func(playwright.PageFrameOptions) playwright.Frame); ok { + r0 = rf(options) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Frame) + } + } + + return r0 +} + +// Frames provides a mock function with given fields: +func (_m *Page) Frames() []playwright.Frame { + ret := _m.Called() + + var r0 []playwright.Frame + if rf, ok := ret.Get(0).(func() []playwright.Frame); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]playwright.Frame) + } + } + + return r0 +} + +// GetAttribute provides a mock function with given fields: selector, name, options +func (_m *Page) GetAttribute(selector string, name string, options ...playwright.PageGetAttributeOptions) (string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, name) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.PageGetAttributeOptions) (string, error)); ok { + return rf(selector, name, options...) + } + if rf, ok := ret.Get(0).(func(string, string, ...playwright.PageGetAttributeOptions) string); ok { + r0 = rf(selector, name, options...) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string, string, ...playwright.PageGetAttributeOptions) error); ok { + r1 = rf(selector, name, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GoBack provides a mock function with given fields: options +func (_m *Page) GoBack(options ...playwright.PageGoBackOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PageGoBackOptions) (playwright.Response, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PageGoBackOptions) playwright.Response); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PageGoBackOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GoForward provides a mock function with given fields: options +func (_m *Page) GoForward(options ...playwright.PageGoForwardOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PageGoForwardOptions) (playwright.Response, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PageGoForwardOptions) playwright.Response); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PageGoForwardOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Goto provides a mock function with given fields: url, options +func (_m *Page) Goto(url string, options ...playwright.PageGotoOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, url) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageGotoOptions) (playwright.Response, error)); ok { + return rf(url, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.PageGotoOptions) playwright.Response); ok { + r0 = rf(url, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.PageGotoOptions) error); ok { + r1 = rf(url, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Hover provides a mock function with given fields: selector, options +func (_m *Page) Hover(selector string, options ...playwright.PageHoverOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageHoverOptions) error); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// InnerHTML provides a mock function with given fields: selector, options +func (_m *Page) InnerHTML(selector string, options ...playwright.PageInnerHTMLOptions) (string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageInnerHTMLOptions) (string, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.PageInnerHTMLOptions) string); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.PageInnerHTMLOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// InnerText provides a mock function with given fields: selector, options +func (_m *Page) InnerText(selector string, options ...playwright.PageInnerTextOptions) (string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageInnerTextOptions) (string, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.PageInnerTextOptions) string); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.PageInnerTextOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// InputValue provides a mock function with given fields: selector, options +func (_m *Page) InputValue(selector string, options ...playwright.FrameInputValueOptions) (string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameInputValueOptions) (string, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameInputValueOptions) string); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameInputValueOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsChecked provides a mock function with given fields: selector, options +func (_m *Page) IsChecked(selector string, options ...playwright.FrameIsCheckedOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsCheckedOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsCheckedOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsCheckedOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsClosed provides a mock function with given fields: +func (_m *Page) IsClosed() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// IsDisabled provides a mock function with given fields: selector, options +func (_m *Page) IsDisabled(selector string, options ...playwright.FrameIsDisabledOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsDisabledOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsDisabledOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsDisabledOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsEditable provides a mock function with given fields: selector, options +func (_m *Page) IsEditable(selector string, options ...playwright.FrameIsEditableOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsEditableOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsEditableOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsEditableOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsEnabled provides a mock function with given fields: selector, options +func (_m *Page) IsEnabled(selector string, options ...playwright.FrameIsEnabledOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsEnabledOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsEnabledOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsEnabledOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsHidden provides a mock function with given fields: selector, options +func (_m *Page) IsHidden(selector string, options ...playwright.FrameIsHiddenOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsHiddenOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsHiddenOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsHiddenOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsVisible provides a mock function with given fields: selector, options +func (_m *Page) IsVisible(selector string, options ...playwright.FrameIsVisibleOptions) (bool, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsVisibleOptions) (bool, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameIsVisibleOptions) bool); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameIsVisibleOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Keyboard provides a mock function with given fields: +func (_m *Page) Keyboard() playwright.Keyboard { + ret := _m.Called() + + var r0 playwright.Keyboard + if rf, ok := ret.Get(0).(func() playwright.Keyboard); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Keyboard) + } + } + + return r0 +} + +// ListenerCount provides a mock function with given fields: name +func (_m *Page) ListenerCount(name string) int { + ret := _m.Called(name) + + var r0 int + if rf, ok := ret.Get(0).(func(string) int); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// Locator provides a mock function with given fields: selector, options +func (_m *Page) Locator(selector string, options ...playwright.PageLocatorOptions) (playwright.Locator, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Locator + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageLocatorOptions) (playwright.Locator, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.PageLocatorOptions) playwright.Locator); ok { + r0 = rf(selector, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Locator) + } + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.PageLocatorOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MainFrame provides a mock function with given fields: +func (_m *Page) MainFrame() playwright.Frame { + ret := _m.Called() + + var r0 playwright.Frame + if rf, ok := ret.Get(0).(func() playwright.Frame); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Frame) + } + } + + return r0 +} + +// Mouse provides a mock function with given fields: +func (_m *Page) Mouse() playwright.Mouse { + ret := _m.Called() + + var r0 playwright.Mouse + if rf, ok := ret.Get(0).(func() playwright.Mouse); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Mouse) + } + } + + return r0 +} + +// On provides a mock function with given fields: name, handler +func (_m *Page) On(name string, handler interface{}) { + _m.Called(name, handler) +} + +// Once provides a mock function with given fields: name, handler +func (_m *Page) Once(name string, handler interface{}) { + _m.Called(name, handler) +} + +// Opener provides a mock function with given fields: +func (_m *Page) Opener() (playwright.Page, error) { + ret := _m.Called() + + var r0 playwright.Page + var r1 error + if rf, ok := ret.Get(0).(func() (playwright.Page, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() playwright.Page); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Page) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PDF provides a mock function with given fields: options +func (_m *Page) PDF(options ...playwright.PagePdfOptions) ([]byte, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PagePdfOptions) ([]byte, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PagePdfOptions) []byte); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PagePdfOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Pause provides a mock function with given fields: +func (_m *Page) Pause() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Press provides a mock function with given fields: selector, key, options +func (_m *Page) Press(selector string, key string, options ...playwright.PagePressOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, key) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.PagePressOptions) error); ok { + r0 = rf(selector, key, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// QuerySelector provides a mock function with given fields: selector +func (_m *Page) QuerySelector(selector string) (playwright.ElementHandle, error) { + ret := _m.Called(selector) + + var r0 playwright.ElementHandle + var r1 error + if rf, ok := ret.Get(0).(func(string) (playwright.ElementHandle, error)); ok { + return rf(selector) + } + if rf, ok := ret.Get(0).(func(string) playwright.ElementHandle); ok { + r0 = rf(selector) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.ElementHandle) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(selector) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// QuerySelectorAll provides a mock function with given fields: selector +func (_m *Page) QuerySelectorAll(selector string) ([]playwright.ElementHandle, error) { + ret := _m.Called(selector) + + var r0 []playwright.ElementHandle + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]playwright.ElementHandle, error)); ok { + return rf(selector) + } + if rf, ok := ret.Get(0).(func(string) []playwright.ElementHandle); ok { + r0 = rf(selector) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]playwright.ElementHandle) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(selector) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Reload provides a mock function with given fields: options +func (_m *Page) Reload(options ...playwright.PageReloadOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PageReloadOptions) (playwright.Response, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PageReloadOptions) playwright.Response); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PageReloadOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoveListener provides a mock function with given fields: name, handler +func (_m *Page) RemoveListener(name string, handler interface{}) { + _m.Called(name, handler) +} + +// Route provides a mock function with given fields: url, handler +func (_m *Page) Route(url interface{}, handler func(playwright.Route, playwright.Request)) error { + ret := _m.Called(url, handler) + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}, func(playwright.Route, playwright.Request)) error); ok { + r0 = rf(url, handler) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Screenshot provides a mock function with given fields: options +func (_m *Page) Screenshot(options ...playwright.PageScreenshotOptions) ([]byte, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PageScreenshotOptions) ([]byte, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PageScreenshotOptions) []byte); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PageScreenshotOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SelectOption provides a mock function with given fields: selector, values, options +func (_m *Page) SelectOption(selector string, values playwright.SelectOptionValues, options ...playwright.FrameSelectOptionOptions) ([]string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, values) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string, playwright.SelectOptionValues, ...playwright.FrameSelectOptionOptions) ([]string, error)); ok { + return rf(selector, values, options...) + } + if rf, ok := ret.Get(0).(func(string, playwright.SelectOptionValues, ...playwright.FrameSelectOptionOptions) []string); ok { + r0 = rf(selector, values, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(string, playwright.SelectOptionValues, ...playwright.FrameSelectOptionOptions) error); ok { + r1 = rf(selector, values, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SetChecked provides a mock function with given fields: selector, checked, options +func (_m *Page) SetChecked(selector string, checked bool, options ...playwright.FrameSetCheckedOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, checked) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, bool, ...playwright.FrameSetCheckedOptions) error); ok { + r0 = rf(selector, checked, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetContent provides a mock function with given fields: content, options +func (_m *Page) SetContent(content string, options ...playwright.PageSetContentOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, content) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageSetContentOptions) error); ok { + r0 = rf(content, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetDefaultNavigationTimeout provides a mock function with given fields: timeout +func (_m *Page) SetDefaultNavigationTimeout(timeout float64) { + _m.Called(timeout) +} + +// SetDefaultTimeout provides a mock function with given fields: timeout +func (_m *Page) SetDefaultTimeout(timeout float64) { + _m.Called(timeout) +} + +// SetExtraHTTPHeaders provides a mock function with given fields: headers +func (_m *Page) SetExtraHTTPHeaders(headers map[string]string) error { + ret := _m.Called(headers) + + var r0 error + if rf, ok := ret.Get(0).(func(map[string]string) error); ok { + r0 = rf(headers) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetInputFiles provides a mock function with given fields: selector, files, options +func (_m *Page) SetInputFiles(selector string, files []playwright.InputFile, options ...playwright.FrameSetInputFilesOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, files) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, []playwright.InputFile, ...playwright.FrameSetInputFilesOptions) error); ok { + r0 = rf(selector, files, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetViewportSize provides a mock function with given fields: width, height +func (_m *Page) SetViewportSize(width int, height int) error { + ret := _m.Called(width, height) + + var r0 error + if rf, ok := ret.Get(0).(func(int, int) error); ok { + r0 = rf(width, height) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Tap provides a mock function with given fields: selector, options +func (_m *Page) Tap(selector string, options ...playwright.FrameTapOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameTapOptions) error); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// TextContent provides a mock function with given fields: selector, options +func (_m *Page) TextContent(selector string, options ...playwright.FrameTextContentOptions) (string, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameTextContentOptions) (string, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameTextContentOptions) string); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.FrameTextContentOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Title provides a mock function with given fields: +func (_m *Page) Title() (string, error) { + ret := _m.Called() + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Touchscreen provides a mock function with given fields: +func (_m *Page) Touchscreen() playwright.Touchscreen { + ret := _m.Called() + + var r0 playwright.Touchscreen + if rf, ok := ret.Get(0).(func() playwright.Touchscreen); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Touchscreen) + } + } + + return r0 +} + +// Type provides a mock function with given fields: selector, text, options +func (_m *Page) Type(selector string, text string, options ...playwright.PageTypeOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector, text) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, ...playwright.PageTypeOptions) error); ok { + r0 = rf(selector, text, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// URL provides a mock function with given fields: +func (_m *Page) URL() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Uncheck provides a mock function with given fields: selector, options +func (_m *Page) Uncheck(selector string, options ...playwright.FrameUncheckOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameUncheckOptions) error); ok { + r0 = rf(selector, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Unroute provides a mock function with given fields: url, handler +func (_m *Page) Unroute(url interface{}, handler ...func(playwright.Route, playwright.Request)) error { + _va := make([]interface{}, len(handler)) + for _i := range handler { + _va[_i] = handler[_i] + } + var _ca []interface{} + _ca = append(_ca, url) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}, ...func(playwright.Route, playwright.Request)) error); ok { + r0 = rf(url, handler...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Video provides a mock function with given fields: +func (_m *Page) Video() playwright.Video { + ret := _m.Called() + + var r0 playwright.Video + if rf, ok := ret.Get(0).(func() playwright.Video); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Video) + } + } + + return r0 +} + +// ViewportSize provides a mock function with given fields: +func (_m *Page) ViewportSize() playwright.ViewportSize { + ret := _m.Called() + + var r0 playwright.ViewportSize + if rf, ok := ret.Get(0).(func() playwright.ViewportSize); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(playwright.ViewportSize) + } + + return r0 +} + +// WaitForEvent provides a mock function with given fields: event, predicate +func (_m *Page) WaitForEvent(event string, predicate ...interface{}) interface{} { + var _ca []interface{} + _ca = append(_ca, event) + _ca = append(_ca, predicate...) + ret := _m.Called(_ca...) + + var r0 interface{} + if rf, ok := ret.Get(0).(func(string, ...interface{}) interface{}); ok { + r0 = rf(event, predicate...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// WaitForFunction provides a mock function with given fields: expression, arg, options +func (_m *Page) WaitForFunction(expression string, arg interface{}, options ...playwright.FrameWaitForFunctionOptions) (playwright.JSHandle, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, expression, arg) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.JSHandle + var r1 error + if rf, ok := ret.Get(0).(func(string, interface{}, ...playwright.FrameWaitForFunctionOptions) (playwright.JSHandle, error)); ok { + return rf(expression, arg, options...) + } + if rf, ok := ret.Get(0).(func(string, interface{}, ...playwright.FrameWaitForFunctionOptions) playwright.JSHandle); ok { + r0 = rf(expression, arg, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.JSHandle) + } + } + + if rf, ok := ret.Get(1).(func(string, interface{}, ...playwright.FrameWaitForFunctionOptions) error); ok { + r1 = rf(expression, arg, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// WaitForLoadState provides a mock function with given fields: state +func (_m *Page) WaitForLoadState(state ...string) { + _va := make([]interface{}, len(state)) + for _i := range state { + _va[_i] = state[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + _m.Called(_ca...) +} + +// WaitForNavigation provides a mock function with given fields: options +func (_m *Page) WaitForNavigation(options ...playwright.PageWaitForNavigationOptions) (playwright.Response, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func(...playwright.PageWaitForNavigationOptions) (playwright.Response, error)); ok { + return rf(options...) + } + if rf, ok := ret.Get(0).(func(...playwright.PageWaitForNavigationOptions) playwright.Response); ok { + r0 = rf(options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func(...playwright.PageWaitForNavigationOptions) error); ok { + r1 = rf(options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// WaitForRequest provides a mock function with given fields: url, options +func (_m *Page) WaitForRequest(url interface{}, options ...interface{}) playwright.Request { + var _ca []interface{} + _ca = append(_ca, url) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 playwright.Request + if rf, ok := ret.Get(0).(func(interface{}, ...interface{}) playwright.Request); ok { + r0 = rf(url, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Request) + } + } + + return r0 +} + +// WaitForResponse provides a mock function with given fields: url, options +func (_m *Page) WaitForResponse(url interface{}, options ...interface{}) playwright.Response { + var _ca []interface{} + _ca = append(_ca, url) + _ca = append(_ca, options...) + ret := _m.Called(_ca...) + + var r0 playwright.Response + if rf, ok := ret.Get(0).(func(interface{}, ...interface{}) playwright.Response); ok { + r0 = rf(url, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + return r0 +} + +// WaitForSelector provides a mock function with given fields: selector, options +func (_m *Page) WaitForSelector(selector string, options ...playwright.PageWaitForSelectorOptions) (playwright.ElementHandle, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, selector) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 playwright.ElementHandle + var r1 error + if rf, ok := ret.Get(0).(func(string, ...playwright.PageWaitForSelectorOptions) (playwright.ElementHandle, error)); ok { + return rf(selector, options...) + } + if rf, ok := ret.Get(0).(func(string, ...playwright.PageWaitForSelectorOptions) playwright.ElementHandle); ok { + r0 = rf(selector, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.ElementHandle) + } + } + + if rf, ok := ret.Get(1).(func(string, ...playwright.PageWaitForSelectorOptions) error); ok { + r1 = rf(selector, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// WaitForTimeout provides a mock function with given fields: timeout +func (_m *Page) WaitForTimeout(timeout float64) { + _m.Called(timeout) +} + +// WaitForURL provides a mock function with given fields: url, options +func (_m *Page) WaitForURL(url string, options ...playwright.FrameWaitForURLOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, url) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(string, ...playwright.FrameWaitForURLOptions) error); ok { + r0 = rf(url, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Workers provides a mock function with given fields: +func (_m *Page) Workers() []playwright.Worker { + ret := _m.Called() + + var r0 []playwright.Worker + if rf, ok := ret.Get(0).(func() []playwright.Worker); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]playwright.Worker) + } + } + + return r0 +} + +type mockConstructorTestingTNewPage interface { + mock.TestingT + Cleanup(func()) +} + +// NewPage creates a new instance of Page. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewPage(t mockConstructorTestingTNewPage) *Page { + mock := &Page{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Request.go b/mocks/Request.go new file mode 100644 index 000000000..9c0233e4c --- /dev/null +++ b/mocks/Request.go @@ -0,0 +1,398 @@ +// Code generated by mockery v2.22.1. DO NOT EDIT. + +package mocks + +import ( + playwright "github.com/playwright-community/playwright-go" + mock "github.com/stretchr/testify/mock" +) + +// Request is an autogenerated mock type for the Request type +type Request struct { + mock.Mock +} + +// AllHeaders provides a mock function with given fields: +func (_m *Request) AllHeaders() (map[string]string, error) { + ret := _m.Called() + + var r0 map[string]string + var r1 error + if rf, ok := ret.Get(0).(func() (map[string]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() map[string]string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Failure provides a mock function with given fields: +func (_m *Request) Failure() *playwright.RequestFailure { + ret := _m.Called() + + var r0 *playwright.RequestFailure + if rf, ok := ret.Get(0).(func() *playwright.RequestFailure); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*playwright.RequestFailure) + } + } + + return r0 +} + +// Frame provides a mock function with given fields: +func (_m *Request) Frame() playwright.Frame { + ret := _m.Called() + + var r0 playwright.Frame + if rf, ok := ret.Get(0).(func() playwright.Frame); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Frame) + } + } + + return r0 +} + +// HeaderValue provides a mock function with given fields: name +func (_m *Request) HeaderValue(name string) (string, error) { + ret := _m.Called(name) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HeaderValues provides a mock function with given fields: name +func (_m *Request) HeaderValues(name string) ([]string, error) { + ret := _m.Called(name) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) []string); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Headers provides a mock function with given fields: +func (_m *Request) Headers() map[string]string { + ret := _m.Called() + + var r0 map[string]string + if rf, ok := ret.Get(0).(func() map[string]string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]string) + } + } + + return r0 +} + +// HeadersArray provides a mock function with given fields: +func (_m *Request) HeadersArray() (playwright.HeadersArray, error) { + ret := _m.Called() + + var r0 playwright.HeadersArray + var r1 error + if rf, ok := ret.Get(0).(func() (playwright.HeadersArray, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() playwright.HeadersArray); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.HeadersArray) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IsNavigationRequest provides a mock function with given fields: +func (_m *Request) IsNavigationRequest() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// Method provides a mock function with given fields: +func (_m *Request) Method() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// PostData provides a mock function with given fields: +func (_m *Request) PostData() (string, error) { + ret := _m.Called() + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PostDataBuffer provides a mock function with given fields: +func (_m *Request) PostDataBuffer() ([]byte, error) { + ret := _m.Called() + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []byte); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PostDataJSON provides a mock function with given fields: v +func (_m *Request) PostDataJSON(v interface{}) error { + ret := _m.Called(v) + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}) error); ok { + r0 = rf(v) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RedirectedFrom provides a mock function with given fields: +func (_m *Request) RedirectedFrom() playwright.Request { + ret := _m.Called() + + var r0 playwright.Request + if rf, ok := ret.Get(0).(func() playwright.Request); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Request) + } + } + + return r0 +} + +// RedirectedTo provides a mock function with given fields: +func (_m *Request) RedirectedTo() playwright.Request { + ret := _m.Called() + + var r0 playwright.Request + if rf, ok := ret.Get(0).(func() playwright.Request); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Request) + } + } + + return r0 +} + +// ResourceType provides a mock function with given fields: +func (_m *Request) ResourceType() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Response provides a mock function with given fields: +func (_m *Request) Response() (playwright.Response, error) { + ret := _m.Called() + + var r0 playwright.Response + var r1 error + if rf, ok := ret.Get(0).(func() (playwright.Response, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() playwright.Response); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(playwright.Response) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Sizes provides a mock function with given fields: +func (_m *Request) Sizes() (*playwright.RequestSizesResult, error) { + ret := _m.Called() + + var r0 *playwright.RequestSizesResult + var r1 error + if rf, ok := ret.Get(0).(func() (*playwright.RequestSizesResult, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *playwright.RequestSizesResult); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*playwright.RequestSizesResult) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Timing provides a mock function with given fields: +func (_m *Request) Timing() *playwright.ResourceTiming { + ret := _m.Called() + + var r0 *playwright.ResourceTiming + if rf, ok := ret.Get(0).(func() *playwright.ResourceTiming); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*playwright.ResourceTiming) + } + } + + return r0 +} + +// URL provides a mock function with given fields: +func (_m *Request) URL() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +type mockConstructorTestingTNewRequest interface { + mock.TestingT + Cleanup(func()) +} + +// NewRequest creates a new instance of Request. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRequest(t mockConstructorTestingTNewRequest) *Request { + mock := &Request{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 8ab18fd75..aac86f275 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -58,6 +58,7 @@ type IDPAccount struct { TargetURL string `ini:"target_url"` DisableRememberDevice bool `ini:"disable_remember_device"` // used by Okta DisableSessions bool `ini:"disable_sessions"` // used by Okta + Headless bool `ini:"headless"` // used by browser Prompter string `ini:"prompter"` } diff --git a/pkg/provider/browser/browser.go b/pkg/provider/browser/browser.go index 32a8e687e..83314c971 100644 --- a/pkg/provider/browser/browser.go +++ b/pkg/provider/browser/browser.go @@ -2,6 +2,7 @@ package browser import ( "errors" + "fmt" "net/url" "regexp" @@ -15,11 +16,12 @@ var logger = logrus.WithField("provider", "browser") // Client client for browser based Identity Provider type Client struct { + Headless bool } // New create new browser based client func New(idpAccount *cfg.IDPAccount) (*Client, error) { - return &Client{}, nil + return &Client{Headless: idpAccount.Headless}, nil } func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) { @@ -31,7 +33,7 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) // TODO: provide some overrides for this window launchOptions := playwright.BrowserTypeLaunchOptions{ - Headless: playwright.Bool(false), + Headless: playwright.Bool(cl.Headless), } // currently using Chromium as it is widely supported for Identity providers @@ -47,6 +49,20 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) return "", err } + defer func() { + logger.Info("clean up browser") + if err := browser.Close(); err != nil { + logger.Info("Error when closing browser", err) + } + if err := pw.Stop(); err != nil { + logger.Info("Error when stopping pm", err) + } + }() + + return getSAMLResponse(page, loginDetails) +} + +var getSAMLResponse = func(page playwright.Page, loginDetails *creds.LoginDetails) (string, error) { logger.WithField("URL", loginDetails.URL).Info("opening browser") if _, err := page.Goto(loginDetails.URL); err != nil { @@ -56,11 +72,12 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) // https://docs.aws.amazon.com/general/latest/gr/signin-service.html // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Ningxia.html // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Beijing.html - signin_re, err := regexp.Compile(`https:\/\/((.*\.)?signin\.(aws\.amazon\.com|amazonaws-us-gov\.com|amazonaws\.cn))\/saml`) + signin_re, err := signinRegex() if err != nil { return "", err } + fmt.Println("waiting ...") r := page.WaitForRequest(signin_re) data, err := r.PostData() if err != nil { @@ -72,18 +89,16 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) return "", err } - logger.Info("clean up browser") - - if err = browser.Close(); err != nil { - return "", err - } - if err = pw.Stop(); err != nil { - return "", err - } - return values.Get("SAMLResponse"), nil } +func signinRegex() (*regexp.Regexp, error) { + // https://docs.aws.amazon.com/general/latest/gr/signin-service.html + // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Ningxia.html + // https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Beijing.html + return regexp.Compile(`https:\/\/((.*\.)?signin\.(aws\.amazon\.com|amazonaws-us-gov\.com|amazonaws\.cn))\/saml`) +} + func (cl *Client) Validate(loginDetails *creds.LoginDetails) error { if loginDetails.URL == "" { diff --git a/pkg/provider/browser/browser_test.go b/pkg/provider/browser/browser_test.go new file mode 100644 index 000000000..7537713c6 --- /dev/null +++ b/pkg/provider/browser/browser_test.go @@ -0,0 +1,43 @@ +package browser + +import ( + "testing" + + "github.com/playwright-community/playwright-go" + "github.com/stretchr/testify/assert" + "github.com/versent/saml2aws/v2/pkg/cfg" + "github.com/versent/saml2aws/v2/pkg/creds" +) + +func TestValidate(t *testing.T) { + getSAMLResponse = fakeSAMLResponse + account := &cfg.IDPAccount{ + Headless: true, + } + client, err := New(account) + assert.Nil(t, err) + loginDetails := &creds.LoginDetails{ + URL: "https://google.com/", + } + resp, err := client.Authenticate(loginDetails) + assert.Nil(t, err) + assert.Equal(t, resp, "foo") +} + +func fakeSAMLResponse(page playwright.Page, loginDetails *creds.LoginDetails) (string, error) { + return "foo", nil +} + +func TestSigninRegex1(t *testing.T) { + regex, err := signinRegex() + assert.Nil(t, err) + match := regex.MatchString("https://signin.aws.amazon.com/saml") + assert.True(t, match) +} + +func TestSigninRegexFail(t *testing.T) { + regex, err := signinRegex() + assert.Nil(t, err) + match := regex.MatchString("https://google.com/") + assert.False(t, match) +} From fd7f85434b6d44346fa58d7a6eb567fa6465a9ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:09:43 +0000 Subject: [PATCH 47/54] chore(deps): bump github.com/aws/aws-sdk-go from 1.44.220 to 1.44.225 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.220 to 1.44.225. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.44.220...v1.44.225) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index e9b475323..40a7462d6 100644 --- a/go.mod +++ b/go.mod @@ -9,10 +9,11 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/alecthomas/kingpin v2.2.6+incompatible github.com/avast/retry-go v3.0.0+incompatible - github.com/aws/aws-sdk-go v1.44.220 + github.com/aws/aws-sdk-go v1.44.225 github.com/beevik/etree v1.1.0 github.com/danieljoos/wincred v1.1.2 github.com/google/uuid v1.3.0 + github.com/h2non/gock v1.2.0 github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621 github.com/marshallbrekka/go-u2fhost v0.0.0-20210111072507-3ccdec8c8105 github.com/mitchellh/go-homedir v1.1.0 @@ -38,7 +39,6 @@ require ( github.com/go-stack/stack v1.8.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect - github.com/h2non/gock v1.2.0 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect diff --git a/go.sum b/go.sum index 9d5148969..6321eb570 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/aws/aws-sdk-go v1.44.220 h1:yAj99qAt0Htjle9Up3DglgHfOP77lmFPrElA4jKnrBo= -github.com/aws/aws-sdk-go v1.44.220/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.225 h1:JNJpUg+M1cm4jtKnyex//Mw1Rv8QN/kWT3dtr+oLdW4= +github.com/aws/aws-sdk-go v1.44.225/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/bearsh/hid v1.3.0 h1:GLNa8hvEzJxzQEEpheDUr2SivvH7iwTrJrDhFKutfX8= github.com/bearsh/hid v1.3.0/go.mod h1:KbQByg8WfPr92v7aaKAHTtZUEVG7e2XRpcF8+TopQv8= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= @@ -125,6 +125,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= From a424204b9f76c16f28830dde5f548e12c2b83505 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:00:46 +0000 Subject: [PATCH 48/54] chore(deps): bump actions/setup-go from 3 to 4 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/go.yml | 6 +++--- .github/workflows/release.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3ca625fee..f3bf22aed 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.20.x @@ -45,7 +45,7 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.20.x @@ -68,7 +68,7 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.20.x diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f76f30ef..18a9b69de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.20.x From f0ea15ed8254198677449c17472f6d36e6bcd1b0 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:30:51 -0400 Subject: [PATCH 49/54] split coverage report generation and upload --- .github/workflows/go.yml | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f3bf22aed..b4a03d30f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -28,13 +28,13 @@ jobs: run: | go install github.com/playwright-community/playwright-go/cmd/playwright playwright install --with-deps - go test -v ./... -coverprofile=coverage.txt -covermode=atomic + go test -v ./... -coverprofile=${{ matrix.os }}_coverage.txt -covermode=atomic - - name: Codecov - uses: codecov/codecov-action@v3 + - name: Upload coverage report + uses: actions/upload-artifact@v3 with: - file: coverage.txt - flags: unittests + name: reports + path: ${{ matrix.os }}_coverage.txt - name: Install run: go install ./cmd/saml2aws @@ -57,6 +57,25 @@ jobs: with: version: v1.51.2 + coverage: + name: coverage + permissions: + actions: read + runs-on: ubuntu-latest + needs: [build] + steps: + - name: Download coverage reports + uses: actions/download-artifact@v3 + with: + name: reports + path: reports + + - name: Codecov + uses: codecov/codecov-action@v3 + with: + directory: reports + flags: unittests + release-build: name: release-build strategy: From 810dfaf440dc26dd1abb63ec340e59b341b28c21 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:37:49 -0400 Subject: [PATCH 50/54] use short retention and ensure no coverage file is an error --- .github/workflows/go.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index b4a03d30f..1100f49c8 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -35,6 +35,8 @@ jobs: with: name: reports path: ${{ matrix.os }}_coverage.txt + if-no-files-found: error + retention-days: 1 - name: Install run: go install ./cmd/saml2aws From e039789bea0485995b61520c5ffc0f2c443dc078 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:59:11 -0400 Subject: [PATCH 51/54] try with contents: read too --- .github/workflows/go.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1100f49c8..1d4db7d24 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -62,6 +62,7 @@ jobs: coverage: name: coverage permissions: + contents: read actions: read runs-on: ubuntu-latest needs: [build] From 8cfef607e1f915d261e760e49837895f51a04071 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 21 Mar 2023 23:16:35 -0400 Subject: [PATCH 52/54] use a checkout also --- .github/workflows/go.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1d4db7d24..d58c3f081 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -67,6 +67,7 @@ jobs: runs-on: ubuntu-latest needs: [build] steps: + - uses: actions/checkout@v3 - name: Download coverage reports uses: actions/download-artifact@v3 with: From 5a8b9947a340ffd6e421c60510b76d330215d766 Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Wed, 22 Mar 2023 08:46:24 -0400 Subject: [PATCH 53/54] try without actions: read --- .github/workflows/go.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d58c3f081..b031fe73b 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -63,7 +63,6 @@ jobs: name: coverage permissions: contents: read - actions: read runs-on: ubuntu-latest needs: [build] steps: From bfba581652bd07568b2cecb9098b450f48aa1e1d Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Thu, 23 Mar 2023 14:26:09 -0400 Subject: [PATCH 54/54] empty