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:
Joshua Casey
2024-05-31 16:24:11 -05:00
committed by Ryan Richard
parent e3d8c71f97
commit 58b4ecc0aa
22 changed files with 200 additions and 89 deletions

View File

@@ -6,7 +6,6 @@ package upstreamgithub
import (
"context"
"errors"
"fmt"
"net/http"
@@ -18,6 +17,7 @@ import (
"go.pinniped.dev/internal/federationdomain/downstreamsubject"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/githubclient"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/setutil"
)
@@ -66,7 +66,7 @@ func New(config ProviderConfig) *Provider {
}
}
func (p *Provider) GetName() string {
func (p *Provider) GetResourceName() string {
return p.c.Name
}
@@ -147,7 +147,20 @@ func (p *Provider) GetUser(ctx context.Context, accessToken string, idpDisplayNa
}
if !p.c.AllowedOrganizations.Empty() && !p.c.AllowedOrganizations.HasAnyIgnoringCase(orgMembership) {
return nil, errors.New("user is not allowed to log in due to organization membership policy")
plog.Warning("user is not allowed to log in due to organization membership policy", // do not log username to avoid PII
"userBelongsToOrganizations", orgMembership,
"configuredAllowedOrganizations", p.c.AllowedOrganizations,
"identityProviderDisplayName", idpDisplayName,
"identityProviderResourceName", p.GetResourceName())
plog.Trace("user is not allowed to log in due to organization membership policy", // okay to log PII at trace level
"githubLogin", userInfo.Login,
"githubID", userInfo.ID,
"calculatedUsername", githubUser.Username,
"userBelongsToOrganizations", orgMembership,
"configuredAllowedOrganizations", p.c.AllowedOrganizations,
"identityProviderDisplayName", idpDisplayName,
"identityProviderResourceName", p.GetResourceName())
return nil, upstreamprovider.NewGitHubLoginDeniedError("user is not allowed to log in due to organization membership policy")
}
teamMembership, err := githubClient.GetTeamMembership(ctx, p.c.AllowedOrganizations)

View File

@@ -74,7 +74,7 @@ func TestGitHubProvider(t *testing.T) {
},
}, subject.GetConfig())
require.Equal(t, "foo", subject.GetName())
require.Equal(t, "foo", subject.GetResourceName())
require.Equal(t, types.UID("resource-uid-12345"), subject.GetResourceUID())
require.Equal(t, "fake-client-id", subject.GetClientID())
require.Equal(t, "fake-client-id", subject.GetClientID())
@@ -205,7 +205,8 @@ func TestGetUser(t *testing.T) {
buildGitHubClientError error
buildMockResponses func(hubInterface *mockgithubclient.MockGitHubInterface)
wantUser *upstreamprovider.GitHubUser
wantErr string
wantErrMsg string
wantErr error
}{
{
name: "happy path with username=login:id",
@@ -303,7 +304,7 @@ func TestGetUser(t *testing.T) {
}, nil)
mockGitHubInterface.EXPECT().GetOrgMembership(someContext).Return([]string{"disallowed-org"}, nil)
},
wantErr: "user is not allowed to log in due to organization membership policy",
wantErr: upstreamprovider.NewGitHubLoginDeniedError("user is not allowed to log in due to organization membership policy"),
},
{
name: "happy path with groups=name",
@@ -390,7 +391,7 @@ func TestGetUser(t *testing.T) {
HttpClient: someHttpClient,
},
buildGitHubClientError: errors.New("error from building a github client"),
wantErr: "error from building a github client",
wantErrMsg: "error from building a github client",
},
{
name: "returns errors from githubClient.GetUserInfo()",
@@ -401,7 +402,7 @@ func TestGetUser(t *testing.T) {
buildMockResponses: func(mockGitHubInterface *mockgithubclient.MockGitHubInterface) {
mockGitHubInterface.EXPECT().GetUserInfo(someContext).Return(nil, errors.New("error from githubClient.GetUserInfo"))
},
wantErr: "error from githubClient.GetUserInfo",
wantErrMsg: "error from githubClient.GetUserInfo",
},
{
name: "returns errors from githubClient.GetOrgMembership()",
@@ -414,7 +415,7 @@ func TestGetUser(t *testing.T) {
mockGitHubInterface.EXPECT().GetUserInfo(someContext).Return(&githubclient.UserInfo{}, nil)
mockGitHubInterface.EXPECT().GetOrgMembership(someContext).Return(nil, errors.New("error from githubClient.GetOrgMembership"))
},
wantErr: "error from githubClient.GetOrgMembership",
wantErrMsg: "error from githubClient.GetOrgMembership",
},
{
name: "returns errors from githubClient.GetTeamMembership()",
@@ -428,7 +429,7 @@ func TestGetUser(t *testing.T) {
mockGitHubInterface.EXPECT().GetOrgMembership(someContext).Return(nil, nil)
mockGitHubInterface.EXPECT().GetTeamMembership(someContext, gomock.Any()).Return(nil, errors.New("error from githubClient.GetTeamMembership"))
},
wantErr: "error from githubClient.GetTeamMembership",
wantErrMsg: "error from githubClient.GetTeamMembership",
},
{
name: "bad configuration: UsernameAttribute",
@@ -443,7 +444,7 @@ func TestGetUser(t *testing.T) {
ID: "some-github-id",
}, nil)
},
wantErr: "bad configuration: unknown GitHub username attribute: this-is-not-legal-value-from-the-enum",
wantErrMsg: "bad configuration: unknown GitHub username attribute: this-is-not-legal-value-from-the-enum",
},
{
name: "bad configuration: GroupNameAttribute",
@@ -467,7 +468,7 @@ func TestGetUser(t *testing.T) {
},
}, nil)
},
wantErr: "bad configuration: unknown GitHub group name attribute: this-is-not-legal-value-from-the-enum",
wantErrMsg: "bad configuration: unknown GitHub group name attribute: this-is-not-legal-value-from-the-enum",
},
}
for _, test := range tests {
@@ -493,13 +494,18 @@ func TestGetUser(t *testing.T) {
}
actualUser, actualErr := p.GetUser(context.Background(), accessToken, idpDisplayName)
if test.wantErr != "" {
require.EqualError(t, actualErr, test.wantErr)
switch {
case test.wantErrMsg != "":
require.EqualError(t, actualErr, test.wantErrMsg)
require.Nil(t, actualUser)
return
case test.wantErr != nil:
require.Equal(t, test.wantErr, actualErr)
require.Nil(t, actualUser)
default:
require.NoError(t, actualErr)
require.Equal(t, test.wantUser, actualUser)
}
require.NoError(t, actualErr)
require.Equal(t, test.wantUser, actualUser)
})
}
}