Skip to content

Commit c94ceb6

Browse files
committed
feat(scim): generate SCIM token
1 parent cd7a474 commit c94ceb6

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

internal/models/sso.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package models
22

33
import (
4+
"crypto/rand"
45
"crypto/sha256"
56
"database/sql"
67
"database/sql/driver"
@@ -43,9 +44,12 @@ func (p SSOProvider) Type() string {
4344
return "saml"
4445
}
4546

46-
func (p *SSOProvider) UpdateSCIMToken(token string) {
47+
func (p *SSOProvider) GenerateSCIMToken() string {
48+
token := rand.Text()
4749
hash := toSHA256(token)
4850
p.SCIMTokenHash = &hash
51+
52+
return token
4953
}
5054

5155
func toSHA256(token string) string {

internal/models/sso_test.go

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package models
22

33
import (
4+
"crypto/sha256"
5+
"encoding/base32"
6+
"encoding/hex"
47
"net/url"
58
"slices"
69
"testing"
@@ -470,12 +473,7 @@ func (ts *SSOTestSuite) TestFindSSOProviderByResourceID() {
470473
}
471474
}
472475

473-
func (ts *SSOTestSuite) TestUpdateSCIMToken() {
474-
hashes := map[string]string{
475-
"scim_test_token": "dcbcd9ffd696ae1f2ee0f035fa17680d78175020a5fa1aadc758dbd681e0fe1d",
476-
"scim_rotated_token": "289adb37f8946571bb4aea1e663281126c7f2d84d929ff09429fcaa1eb3f27bf",
477-
}
478-
476+
func (ts *SSOTestSuite) TestGenerateSCIMToken() {
479477
provider := &SSOProvider{
480478
SAMLProvider: SAMLProvider{
481479
EntityID: "https://example.com/saml/metadata/",
@@ -484,23 +482,40 @@ func (ts *SSOTestSuite) TestUpdateSCIMToken() {
484482
}
485483
require.Nil(ts.T(), provider.SCIMTokenHash)
486484

487-
for token, hash := range hashes {
488-
provider.UpdateSCIMToken(token)
485+
token := provider.GenerateSCIMToken()
486+
487+
ts.Run("returns at least 128 bits of base32 randomness", func() {
488+
decoded, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(token)
489+
490+
require.NoError(ts.T(), err)
491+
require.GreaterOrEqual(ts.T(), len(decoded), 16)
492+
})
493+
494+
ts.Run("stores the SHA-256 digest of the token", func() {
495+
sum := sha256.Sum256([]byte(token))
496+
489497
require.NotNil(ts.T(), provider.SCIMTokenHash)
490-
require.Equal(ts.T(), hash, *provider.SCIMTokenHash)
491-
}
498+
require.Equal(ts.T(), hex.EncodeToString(sum[:]), *provider.SCIMTokenHash)
499+
})
500+
501+
ts.Run("never stores the token itself", func() {
502+
require.NotContains(ts.T(), *provider.SCIMTokenHash, token)
503+
})
504+
505+
ts.Run("generates a distinct token on every call", func() {
506+
require.NotEqual(ts.T(), token, provider.GenerateSCIMToken())
507+
})
492508
}
493509

494510
func (ts *SSOTestSuite) TestFindSSOProviderBySCIMToken() {
495-
token := "scim_test_token"
496511
provider := &SSOProvider{
497512
SAMLProvider: SAMLProvider{
498513
EntityID: "https://example.com/saml/metadata/1",
499514
MetadataXML: "<example />",
500515
},
501516
}
502517

503-
provider.UpdateSCIMToken(token)
518+
token := provider.GenerateSCIMToken()
504519
require.NoError(ts.T(), ts.db.Eager().Create(provider))
505520

506521
withoutToken := &SSOProvider{
@@ -533,8 +548,7 @@ func (ts *SSOTestSuite) TestFindSSOProviderBySCIMToken() {
533548
})
534549

535550
ts.Run("rotation stops the previous token from resolving", func() {
536-
newToken := "scim_rotated_token"
537-
provider.UpdateSCIMToken(newToken)
551+
newToken := provider.GenerateSCIMToken()
538552
require.NoError(ts.T(), ts.db.Update(provider))
539553

540554
found, err := FindSSOProviderBySCIMToken(ts.db, newToken)

0 commit comments

Comments
 (0)