0.29.1原版
This commit is contained in:
@@ -0,0 +1,468 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
func TestIdentityProviderStore(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
createdIDP, err := ts.CreateIdentityProvider(ctx, &storepb.IdentityProvider{
|
||||
Uid: "test-github-oauth",
|
||||
Name: "GitHub OAuth",
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
IdentifierFilter: "",
|
||||
Config: &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
AuthUrl: "https://github.com/auth",
|
||||
TokenUrl: "https://github.com/token",
|
||||
UserInfoUrl: "https://github.com/user",
|
||||
Scopes: []string{"login"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "login",
|
||||
DisplayName: "name",
|
||||
Email: "email",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test-github-oauth", createdIDP.Uid)
|
||||
idp, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{
|
||||
ID: &createdIDP.Id,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, idp)
|
||||
require.Equal(t, createdIDP, idp)
|
||||
newName := "My GitHub OAuth"
|
||||
updatedIdp, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProviderV1{
|
||||
ID: idp.Id,
|
||||
Name: &newName,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, newName, updatedIdp.Name)
|
||||
err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{
|
||||
ID: idp.Id,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
idpList, err := ts.ListIdentityProviders(ctx, &store.FindIdentityProvider{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(idpList))
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderGetByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create IDP
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Test IDP", "test-idp"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get by ID
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, found)
|
||||
require.Equal(t, idp.Id, found.Id)
|
||||
require.Equal(t, idp.Name, found.Name)
|
||||
|
||||
// Get by UID
|
||||
foundByUID, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{UID: &idp.Uid})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, foundByUID)
|
||||
require.Equal(t, idp.Id, foundByUID.Id)
|
||||
require.Equal(t, idp.Uid, foundByUID.Uid)
|
||||
|
||||
// Get by non-existent ID
|
||||
nonExistentID := int32(99999)
|
||||
notFound, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &nonExistentID})
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, notFound)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderListMultiple(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create multiple IDPs
|
||||
_, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("GitHub OAuth", "github-oauth"))
|
||||
require.NoError(t, err)
|
||||
_, err = ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Google OAuth", "google-oauth"))
|
||||
require.NoError(t, err)
|
||||
_, err = ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("GitLab OAuth", "gitlab-oauth"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// List all
|
||||
idpList, err := ts.ListIdentityProviders(ctx, &store.FindIdentityProvider{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, idpList, 3)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderListByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create multiple IDPs
|
||||
idp1, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("GitHub OAuth", "github-oauth"))
|
||||
require.NoError(t, err)
|
||||
_, err = ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Google OAuth", "google-oauth"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// List by specific ID
|
||||
idpList, err := ts.ListIdentityProviders(ctx, &store.FindIdentityProvider{ID: &idp1.Id})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, idpList, 1)
|
||||
require.Equal(t, "GitHub OAuth", idpList[0].Name)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderUpdateName(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Original Name", "original-name"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Original Name", idp.Name)
|
||||
|
||||
// Update name
|
||||
newName := "Updated Name"
|
||||
updated, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProviderV1{
|
||||
ID: idp.Id,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
Name: &newName,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Updated Name", updated.Name)
|
||||
|
||||
// Verify update persisted
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Updated Name", found.Name)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderUpdateIdentifierFilter(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Test IDP", "test-idp"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "", idp.IdentifierFilter)
|
||||
|
||||
// Update identifier filter
|
||||
newFilter := "@example.com$"
|
||||
updated, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProviderV1{
|
||||
ID: idp.Id,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
IdentifierFilter: &newFilter,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "@example.com$", updated.IdentifierFilter)
|
||||
|
||||
// Verify update persisted
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "@example.com$", found.IdentifierFilter)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderUpdateConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Test IDP", "test-idp"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update config
|
||||
newConfig := &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "new_client_id",
|
||||
ClientSecret: "new_client_secret",
|
||||
AuthUrl: "https://newprovider.com/auth",
|
||||
TokenUrl: "https://newprovider.com/token",
|
||||
UserInfoUrl: "https://newprovider.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "sub",
|
||||
DisplayName: "name",
|
||||
Email: "email",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
updated, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProviderV1{
|
||||
ID: idp.Id,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
Config: newConfig,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new_client_id", updated.Config.GetOauth2Config().ClientId)
|
||||
require.Equal(t, "new_client_secret", updated.Config.GetOauth2Config().ClientSecret)
|
||||
require.Contains(t, updated.Config.GetOauth2Config().Scopes, "openid")
|
||||
|
||||
// Verify update persisted
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new_client_id", found.Config.GetOauth2Config().ClientId)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderUpdateMultipleFields(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Original", "original"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update multiple fields at once
|
||||
newName := "Updated IDP"
|
||||
newFilter := "^admin@"
|
||||
updated, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProviderV1{
|
||||
ID: idp.Id,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
Name: &newName,
|
||||
IdentifierFilter: &newFilter,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Updated IDP", updated.Name)
|
||||
require.Equal(t, "^admin@", updated.IdentifierFilter)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
idp, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("Test IDP", "test-idp"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Delete
|
||||
err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ID: idp.Id})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify deletion
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, found)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderDeleteNotAffectOthers(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create multiple IDPs
|
||||
idp1, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("IDP 1", "idp-1"))
|
||||
require.NoError(t, err)
|
||||
idp2, err := ts.CreateIdentityProvider(ctx, createTestOAuth2IDP("IDP 2", "idp-2"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Delete first one
|
||||
err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ID: idp1.Id})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify second still exists
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp2.Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, found)
|
||||
require.Equal(t, "IDP 2", found.Name)
|
||||
|
||||
// Verify list only contains second
|
||||
idpList, err := ts.ListIdentityProviders(ctx, &store.FindIdentityProvider{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, idpList, 1)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderOAuth2ConfigScopes(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create IDP with multiple scopes
|
||||
idp, err := ts.CreateIdentityProvider(ctx, &storepb.IdentityProvider{
|
||||
Uid: "multi-scope-oauth",
|
||||
Name: "Multi-Scope OAuth",
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
Config: &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
AuthUrl: "https://provider.com/auth",
|
||||
TokenUrl: "https://provider.com/token",
|
||||
UserInfoUrl: "https://provider.com/userinfo",
|
||||
Scopes: []string{"openid", "profile", "email", "groups"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "sub",
|
||||
DisplayName: "name",
|
||||
Email: "email",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify scopes are preserved
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, found.Config.GetOauth2Config().Scopes, 4)
|
||||
require.Contains(t, found.Config.GetOauth2Config().Scopes, "openid")
|
||||
require.Contains(t, found.Config.GetOauth2Config().Scopes, "groups")
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderFieldMapping(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
// Create IDP with custom field mapping
|
||||
idp, err := ts.CreateIdentityProvider(ctx, &storepb.IdentityProvider{
|
||||
Uid: "custom-field-mapping",
|
||||
Name: "Custom Field Mapping",
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
Config: &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
AuthUrl: "https://provider.com/auth",
|
||||
TokenUrl: "https://provider.com/token",
|
||||
UserInfoUrl: "https://provider.com/userinfo",
|
||||
Scopes: []string{"login"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "preferred_username",
|
||||
DisplayName: "full_name",
|
||||
Email: "email_address",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify field mapping is preserved
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "preferred_username", found.Config.GetOauth2Config().FieldMapping.Identifier)
|
||||
require.Equal(t, "full_name", found.Config.GetOauth2Config().FieldMapping.DisplayName)
|
||||
require.Equal(t, "email_address", found.Config.GetOauth2Config().FieldMapping.Email)
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
func TestIdentityProviderIdentifierFilterPatterns(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ts := NewTestingStore(ctx, t)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
uid string
|
||||
filter string
|
||||
}{
|
||||
{"Domain filter", "domain-filter", "@company\\.com$"},
|
||||
{"Prefix filter", "prefix-filter", "^admin_"},
|
||||
{"Complex regex", "complex-regex", "^[a-z]+@(dept1|dept2)\\.example\\.com$"},
|
||||
{"Empty filter", "empty-filter", ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
idp, err := ts.CreateIdentityProvider(ctx, &storepb.IdentityProvider{
|
||||
Uid: tc.uid,
|
||||
Name: tc.name,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
IdentifierFilter: tc.filter,
|
||||
Config: &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
AuthUrl: "https://provider.com/auth",
|
||||
TokenUrl: "https://provider.com/token",
|
||||
UserInfoUrl: "https://provider.com/userinfo",
|
||||
Scopes: []string{"login"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "sub",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ID: &idp.Id})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.filter, found.IdentifierFilter)
|
||||
|
||||
// Cleanup
|
||||
err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ID: idp.Id})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
ts.Close()
|
||||
}
|
||||
|
||||
// Helper function to create a test OAuth2 IDP.
|
||||
func createTestOAuth2IDP(name, uid string) *storepb.IdentityProvider {
|
||||
return &storepb.IdentityProvider{
|
||||
Uid: uid,
|
||||
Name: name,
|
||||
Type: storepb.IdentityProvider_OAUTH2,
|
||||
IdentifierFilter: "",
|
||||
Config: &storepb.IdentityProviderConfig{
|
||||
Config: &storepb.IdentityProviderConfig_Oauth2Config{
|
||||
Oauth2Config: &storepb.OAuth2Config{
|
||||
ClientId: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
AuthUrl: "https://provider.com/auth",
|
||||
TokenUrl: "https://provider.com/token",
|
||||
UserInfoUrl: "https://provider.com/userinfo",
|
||||
Scopes: []string{"login"},
|
||||
FieldMapping: &storepb.FieldMapping{
|
||||
Identifier: "login",
|
||||
DisplayName: "name",
|
||||
Email: "email",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user