mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-05 23:57:12 +00:00
user sees error msg when GitHub login is denied due to allowed orgs
Also renamed an interface function from GetName to GetResourceName. Co-authored-by: Ryan Richard <richardry@vmware.com>
This commit is contained in:
committed by
Ryan Richard
co-authored by
Ryan Richard
parent
e3d8c71f97
commit
58b4ecc0aa
+10
-7
@@ -17,7 +17,6 @@ import (
|
||||
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
|
||||
"go.pinniped.dev/internal/httputil/httperr"
|
||||
"go.pinniped.dev/internal/idtransform"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||
"go.pinniped.dev/pkg/oidcclient/pkce"
|
||||
@@ -103,7 +102,6 @@ func (p *FederationDomainResolvedGitHubIdentityProvider) LoginFromCallback(
|
||||
) (*resolvedprovider.Identity, *resolvedprovider.IdentityLoginExtras, error) {
|
||||
accessToken, err := p.Provider.ExchangeAuthcode(ctx, authCode, redirectURI)
|
||||
if err != nil {
|
||||
plog.WarningErr("failed to exchange authcode using GitHub API", err, "upstreamName", p.Provider.GetName())
|
||||
return nil, nil, httperr.Wrap(http.StatusBadGateway,
|
||||
"failed to exchange authcode using GitHub API",
|
||||
err,
|
||||
@@ -111,8 +109,14 @@ func (p *FederationDomainResolvedGitHubIdentityProvider) LoginFromCallback(
|
||||
}
|
||||
|
||||
user, err := p.Provider.GetUser(ctx, accessToken, p.GetDisplayName())
|
||||
if err != nil {
|
||||
plog.WarningErr("failed to get user info from GitHub API", err, "upstreamName", p.Provider.GetName())
|
||||
|
||||
if errors.As(err, &upstreamprovider.GitHubLoginDeniedError{}) {
|
||||
// We specifically want errors of type GitHubLoginDeniedError to have a user-displayed message.
|
||||
// Don't wrap the error since we include it in the sprintf here.
|
||||
return nil, nil, httperr.Newf(http.StatusForbidden,
|
||||
"login denied due to configuration on GitHubIdentityProvider with display name %q: %s",
|
||||
p.GetDisplayName(), err)
|
||||
} else if err != nil {
|
||||
return nil, nil, httperr.Wrap(http.StatusUnprocessableEntity,
|
||||
"failed to get user info from GitHub API",
|
||||
err,
|
||||
@@ -151,8 +155,7 @@ func (p *FederationDomainResolvedGitHubIdentityProvider) UpstreamRefresh(
|
||||
// Get the user's GitHub identity and groups again using the cached access token.
|
||||
refreshedUserInfo, err := p.Provider.GetUser(ctx, githubSessionData.UpstreamAccessToken, p.GetDisplayName())
|
||||
if err != nil {
|
||||
plog.WarningErr("failed to refresh user info from GitHub API", err, "upstreamName", p.Provider.GetName())
|
||||
return nil, p.refreshErr(errors.New("failed to refresh user info from GitHub API"))
|
||||
return nil, p.refreshErr(err)
|
||||
}
|
||||
|
||||
if refreshedUserInfo.DownstreamSubject != identity.DownstreamSubject {
|
||||
@@ -172,5 +175,5 @@ func (p *FederationDomainResolvedGitHubIdentityProvider) refreshErr(err error) *
|
||||
return resolvedprovider.ErrUpstreamRefreshError().
|
||||
WithHint("Upstream refresh failed.").
|
||||
WithTrace(err).
|
||||
WithDebugf("provider name: %q, provider type: %q", p.Provider.GetName(), p.GetSessionProviderType())
|
||||
WithDebugf("provider name: %q, provider type: %q", p.Provider.GetResourceName(), p.GetSessionProviderType())
|
||||
}
|
||||
|
||||
+54
-15
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
@@ -125,7 +126,9 @@ func TestLoginFromCallback(t *testing.T) {
|
||||
wantGetUserArgs *oidctestutil.GetUserArgs
|
||||
wantIdentity *resolvedprovider.Identity
|
||||
wantExtras *resolvedprovider.IdentityLoginExtras
|
||||
wantErr string
|
||||
wantErrMsg string
|
||||
wantErrResponseMsg string
|
||||
wantErrStatusCode int
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -176,13 +179,15 @@ func TestLoginFromCallback(t *testing.T) {
|
||||
Authcode: "fake-authcode",
|
||||
RedirectURI: "https://fake-redirect-uri",
|
||||
},
|
||||
wantGetUserCall: false,
|
||||
wantIdentity: nil,
|
||||
wantExtras: nil,
|
||||
wantErr: "failed to exchange authcode using GitHub API: fake authcode exchange error",
|
||||
wantGetUserCall: false,
|
||||
wantIdentity: nil,
|
||||
wantExtras: nil,
|
||||
wantErrMsg: "failed to exchange authcode using GitHub API: fake authcode exchange error",
|
||||
wantErrResponseMsg: "Bad Gateway: failed to exchange authcode using GitHub API",
|
||||
wantErrStatusCode: http.StatusBadGateway,
|
||||
},
|
||||
{
|
||||
name: "error while getting user info",
|
||||
name: "generic error while getting user info",
|
||||
provider: oidctestutil.NewTestUpstreamGitHubIdentityProviderBuilder().
|
||||
WithAccessToken("fake-access-token").
|
||||
WithGetUserError(errors.New("fake user info error")).
|
||||
@@ -202,9 +207,38 @@ func TestLoginFromCallback(t *testing.T) {
|
||||
AccessToken: "fake-access-token",
|
||||
IDPDisplayName: "fake-display-name",
|
||||
},
|
||||
wantIdentity: nil,
|
||||
wantExtras: nil,
|
||||
wantErr: "failed to get user info from GitHub API: fake user info error",
|
||||
wantIdentity: nil,
|
||||
wantExtras: nil,
|
||||
wantErrMsg: "failed to get user info from GitHub API: fake user info error",
|
||||
wantErrResponseMsg: "Unprocessable Entity: failed to get user info from GitHub API",
|
||||
wantErrStatusCode: http.StatusUnprocessableEntity,
|
||||
},
|
||||
{
|
||||
name: "loginDenied error while getting user info",
|
||||
provider: oidctestutil.NewTestUpstreamGitHubIdentityProviderBuilder().
|
||||
WithAccessToken("fake-access-token").
|
||||
WithGetUserError(upstreamprovider.NewGitHubLoginDeniedError("some login denied error")).
|
||||
Build(),
|
||||
idpDisplayName: "fake-display-name",
|
||||
authcode: "fake-authcode",
|
||||
redirectURI: "https://fake-redirect-uri",
|
||||
wantExchangeAuthcodeCall: true,
|
||||
wantExchangeAuthcodeArgs: &oidctestutil.ExchangeAuthcodeArgs{
|
||||
Ctx: uniqueCtx,
|
||||
Authcode: "fake-authcode",
|
||||
RedirectURI: "https://fake-redirect-uri",
|
||||
},
|
||||
wantGetUserCall: true,
|
||||
wantGetUserArgs: &oidctestutil.GetUserArgs{
|
||||
Ctx: uniqueCtx,
|
||||
AccessToken: "fake-access-token",
|
||||
IDPDisplayName: "fake-display-name",
|
||||
},
|
||||
wantIdentity: nil,
|
||||
wantExtras: nil,
|
||||
wantErrMsg: `login denied due to configuration on GitHubIdentityProvider with display name "fake-display-name": some login denied error`,
|
||||
wantErrResponseMsg: `Forbidden: login denied due to configuration on GitHubIdentityProvider with display name "fake-display-name": some login denied error`,
|
||||
wantErrStatusCode: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -238,12 +272,17 @@ func TestLoginFromCallback(t *testing.T) {
|
||||
require.Zero(t, test.provider.GetUserCallCount())
|
||||
}
|
||||
|
||||
if test.wantErr == "" {
|
||||
if test.wantErrResponseMsg == "" {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
errAsResponder, ok := err.(httperr.Responder)
|
||||
require.True(t, ok)
|
||||
require.EqualError(t, errAsResponder, test.wantErr)
|
||||
require.Implements(t, (*httperr.Responder)(nil), err)
|
||||
errAsResponder := err.(httperr.Responder)
|
||||
rec := httptest.NewRecorder()
|
||||
errAsResponder.Respond(rec)
|
||||
require.Equal(t, test.wantErrStatusCode, rec.Code)
|
||||
require.Equal(t, test.wantErrResponseMsg+"\n", rec.Body.String())
|
||||
|
||||
require.EqualError(t, errAsResponder, test.wantErrMsg)
|
||||
}
|
||||
require.Equal(t, test.wantExtras, loginExtras)
|
||||
require.Equal(t, test.wantIdentity, identity)
|
||||
@@ -297,7 +336,7 @@ func TestUpstreamRefresh(t *testing.T) {
|
||||
name: "error while getting user info",
|
||||
provider: oidctestutil.NewTestUpstreamGitHubIdentityProviderBuilder().
|
||||
WithName("fake-provider-name").
|
||||
WithGetUserError(errors.New("any error message")).
|
||||
WithGetUserError(errors.New("fake github GetUser error message")).
|
||||
Build(),
|
||||
identity: &resolvedprovider.Identity{
|
||||
UpstreamUsername: "initial-username",
|
||||
@@ -313,7 +352,7 @@ func TestUpstreamRefresh(t *testing.T) {
|
||||
IDPDisplayName: "fake-display-name",
|
||||
},
|
||||
wantRefreshedIdentity: nil,
|
||||
wantWrappedErr: "failed to refresh user info from GitHub API",
|
||||
wantWrappedErr: "fake github GetUser error message",
|
||||
},
|
||||
{
|
||||
name: "wrong session data type, which should not really happen",
|
||||
|
||||
Reference in New Issue
Block a user