mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
* Add UpdateUser rpc to proto * Differentiate between create and update in github,oidc,saml * Edit updated_by event field to be more generic (used with contexts to capture user modifying records) * Update security issue by removing secrets from user when update/upsert/create (forrest) * Update createUser in resource_command and require force for updates
623 lines
17 KiB
Go
623 lines
17 KiB
Go
/*
|
|
Copyright 2015-2019 Gravitational, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package auth
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
"github.com/gravitational/teleport"
|
|
authority "github.com/gravitational/teleport/lib/auth/testauthority"
|
|
"github.com/gravitational/teleport/lib/backend"
|
|
"github.com/gravitational/teleport/lib/backend/lite"
|
|
"github.com/gravitational/teleport/lib/defaults"
|
|
"github.com/gravitational/teleport/lib/events"
|
|
"github.com/gravitational/teleport/lib/fixtures"
|
|
"github.com/gravitational/teleport/lib/services"
|
|
"github.com/gravitational/teleport/lib/services/suite"
|
|
"github.com/gravitational/teleport/lib/utils"
|
|
|
|
"github.com/coreos/go-oidc/jose"
|
|
"github.com/gravitational/trace"
|
|
"github.com/jonboulle/clockwork"
|
|
. "gopkg.in/check.v1"
|
|
)
|
|
|
|
func TestAPI(t *testing.T) { TestingT(t) }
|
|
|
|
type AuthSuite struct {
|
|
bk backend.Backend
|
|
a *AuthServer
|
|
dataDir string
|
|
mockedAuditLog *events.MockAuditLog
|
|
}
|
|
|
|
var _ = Suite(&AuthSuite{})
|
|
var _ = fmt.Printf
|
|
|
|
func (s *AuthSuite) SetUpSuite(c *C) {
|
|
utils.InitLoggerForTests(testing.Verbose())
|
|
}
|
|
|
|
func (s *AuthSuite) SetUpTest(c *C) {
|
|
var err error
|
|
s.mockedAuditLog = events.NewMockAuditLog(0)
|
|
s.dataDir = c.MkDir()
|
|
s.bk, err = lite.NewWithConfig(context.TODO(), lite.Config{Path: s.dataDir})
|
|
c.Assert(err, IsNil)
|
|
|
|
clusterName, err := services.NewClusterName(services.ClusterNameSpecV2{
|
|
ClusterName: "me.localhost",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
authConfig := &InitConfig{
|
|
ClusterName: clusterName,
|
|
Backend: s.bk,
|
|
Authority: authority.New(),
|
|
SkipPeriodicOperations: true,
|
|
}
|
|
s.a, err = NewAuthServer(authConfig)
|
|
c.Assert(err, IsNil)
|
|
|
|
// set cluster name
|
|
err = s.a.SetClusterName(clusterName)
|
|
c.Assert(err, IsNil)
|
|
|
|
// set static tokens
|
|
staticTokens, err := services.NewStaticTokens(services.StaticTokensSpecV2{
|
|
StaticTokens: []services.ProvisionTokenV1{},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
err = s.a.SetStaticTokens(staticTokens)
|
|
c.Assert(err, IsNil)
|
|
|
|
authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{
|
|
Type: teleport.Local,
|
|
SecondFactor: teleport.OFF,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
|
|
err = s.a.SetAuthPreference(authPreference)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = s.a.SetClusterConfig(services.DefaultClusterConfig())
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *AuthSuite) TearDownTest(c *C) {
|
|
if s.bk != nil {
|
|
s.bk.Close()
|
|
}
|
|
}
|
|
|
|
func (s *AuthSuite) TestSessions(c *C) {
|
|
c.Assert(s.a.UpsertCertAuthority(
|
|
suite.NewTestCA(services.UserCA, "me.localhost")), IsNil)
|
|
|
|
c.Assert(s.a.UpsertCertAuthority(
|
|
suite.NewTestCA(services.HostCA, "me.localhost")), IsNil)
|
|
|
|
user := "user1"
|
|
pass := []byte("abc123")
|
|
|
|
_, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, NotNil)
|
|
|
|
_, _, err = CreateUserAndRole(s.a, user, []string{user})
|
|
c.Assert(err, IsNil)
|
|
|
|
err = s.a.UpsertPassword(user, pass)
|
|
c.Assert(err, IsNil)
|
|
|
|
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(ws, NotNil)
|
|
|
|
out, err := s.a.GetWebSessionInfo(user, ws.GetName())
|
|
c.Assert(err, IsNil)
|
|
ws.SetPriv(nil)
|
|
fixtures.DeepCompare(c, ws, out)
|
|
|
|
err = s.a.DeleteWebSession(user, ws.GetName())
|
|
c.Assert(err, IsNil)
|
|
|
|
_, err = s.a.GetWebSession(user, ws.GetName())
|
|
c.Assert(trace.IsNotFound(err), Equals, true, Commentf("%#v", err))
|
|
}
|
|
|
|
func (s *AuthSuite) TestUserLock(c *C) {
|
|
c.Assert(s.a.UpsertCertAuthority(
|
|
suite.NewTestCA(services.UserCA, "me.localhost")), IsNil)
|
|
|
|
c.Assert(s.a.UpsertCertAuthority(
|
|
suite.NewTestCA(services.HostCA, "me.localhost")), IsNil)
|
|
|
|
user := "user1"
|
|
pass := []byte("abc123")
|
|
|
|
_, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, NotNil)
|
|
|
|
_, _, err = CreateUserAndRole(s.a, user, []string{user})
|
|
c.Assert(err, IsNil)
|
|
|
|
err = s.a.UpsertPassword(user, pass)
|
|
c.Assert(err, IsNil)
|
|
|
|
// successful log in
|
|
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(ws, NotNil)
|
|
|
|
fakeClock := clockwork.NewFakeClock()
|
|
s.a.SetClock(fakeClock)
|
|
|
|
for i := 0; i <= defaults.MaxLoginAttempts; i++ {
|
|
_, err = s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: []byte("wrong pass")},
|
|
})
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
// make sure user is locked
|
|
_, err = s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, ErrorMatches, ".*locked.*")
|
|
|
|
// advance time and make sure we can login again
|
|
fakeClock.Advance(defaults.AccountLockInterval + time.Second)
|
|
|
|
_, err = s.a.AuthenticateWebUser(AuthenticateUserRequest{
|
|
Username: user,
|
|
Pass: &PassCreds{Password: pass},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *AuthSuite) TestTokensCRUD(c *C) {
|
|
c.Assert(s.a.UpsertCertAuthority(
|
|
suite.NewTestCA(services.HostCA, "me.localhost")), IsNil)
|
|
|
|
// before we do anything, we should have 0 tokens
|
|
btokens, err := s.a.GetTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(btokens), Equals, 0)
|
|
|
|
// generate persistent token
|
|
tok, err := s.a.GenerateToken(GenerateTokenRequest{Roles: teleport.Roles{teleport.RoleNode}})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(tok), Equals, 2*TokenLenBytes)
|
|
|
|
tokens, err := s.a.GetTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(tokens), Equals, 1)
|
|
c.Assert(tokens[0].GetName(), Equals, tok)
|
|
|
|
roles, err := s.a.ValidateToken(tok)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(roles.Include(teleport.RoleNode), Equals, true)
|
|
c.Assert(roles.Include(teleport.RoleProxy), Equals, false)
|
|
|
|
// unsuccessful registration (wrong role)
|
|
keys, err := s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: tok,
|
|
HostID: "bad-host-id",
|
|
NodeName: "bad-node-name",
|
|
Role: teleport.RoleProxy,
|
|
})
|
|
c.Assert(keys, IsNil)
|
|
c.Assert(err, NotNil)
|
|
c.Assert(err, ErrorMatches, `node "bad-node-name" \[bad-host-id\] can not join the cluster, the token does not allow "Proxy" role`)
|
|
|
|
// generate predefined token
|
|
customToken := "custom-token"
|
|
tok, err = s.a.GenerateToken(GenerateTokenRequest{Roles: teleport.Roles{teleport.RoleNode}, Token: customToken})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tok, Equals, customToken)
|
|
|
|
roles, err = s.a.ValidateToken(tok)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(roles.Include(teleport.RoleNode), Equals, true)
|
|
c.Assert(roles.Include(teleport.RoleProxy), Equals, false)
|
|
|
|
err = s.a.DeleteToken(customToken)
|
|
c.Assert(err, IsNil)
|
|
|
|
// generate multi-use token with long TTL:
|
|
multiUseToken, err := s.a.GenerateToken(GenerateTokenRequest{Roles: teleport.Roles{teleport.RoleProxy}, TTL: time.Hour})
|
|
c.Assert(err, IsNil)
|
|
_, err = s.a.ValidateToken(multiUseToken)
|
|
c.Assert(err, IsNil)
|
|
|
|
// use it twice:
|
|
keys, err = s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: multiUseToken,
|
|
HostID: "once",
|
|
NodeName: "node-name",
|
|
Role: teleport.RoleProxy,
|
|
AdditionalPrincipals: []string{"example.com"},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
|
|
// along the way, make sure that additional principals work
|
|
key, _, _, _, err := ssh.ParseAuthorizedKey(keys.Cert)
|
|
c.Assert(err, IsNil)
|
|
hostCert := key.(*ssh.Certificate)
|
|
comment := Commentf("can't find example.com in %v", hostCert.ValidPrincipals)
|
|
c.Assert(utils.SliceContainsStr(hostCert.ValidPrincipals, "example.com"), Equals, true, comment)
|
|
|
|
_, err = s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: multiUseToken,
|
|
HostID: "twice",
|
|
NodeName: "node-name",
|
|
Role: teleport.RoleProxy,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
|
|
// try to use after TTL:
|
|
s.a.SetClock(clockwork.NewFakeClockAt(time.Now().UTC().Add(time.Hour + 1)))
|
|
_, err = s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: multiUseToken,
|
|
HostID: "late.bird",
|
|
NodeName: "node-name",
|
|
Role: teleport.RoleProxy,
|
|
})
|
|
c.Assert(err, ErrorMatches, `"node-name" \[late.bird\] can not join the cluster with role Proxy, the token is not valid`)
|
|
|
|
// expired token should be gone now
|
|
err = s.a.DeleteToken(multiUseToken)
|
|
c.Assert(trace.IsNotFound(err), Equals, true, Commentf("%#v", err))
|
|
|
|
// lets use static tokens now
|
|
roles = teleport.Roles{teleport.RoleProxy}
|
|
st, err := services.NewStaticTokens(services.StaticTokensSpecV2{
|
|
StaticTokens: []services.ProvisionTokenV1{services.ProvisionTokenV1{
|
|
Token: "static-token-value",
|
|
Roles: roles,
|
|
Expires: time.Unix(0, 0).UTC(),
|
|
}},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
err = s.a.SetStaticTokens(st)
|
|
c.Assert(err, IsNil)
|
|
_, err = s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: "static-token-value",
|
|
HostID: "static.host",
|
|
NodeName: "node-name",
|
|
Role: teleport.RoleProxy,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
_, err = s.a.RegisterUsingToken(RegisterUsingTokenRequest{
|
|
Token: "static-token-value",
|
|
HostID: "wrong.role",
|
|
NodeName: "node-name",
|
|
Role: teleport.RoleAuth,
|
|
})
|
|
c.Assert(err, NotNil)
|
|
r, err := s.a.ValidateToken("static-token-value")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, roles)
|
|
|
|
// List tokens (should see 2: one static, one regular)
|
|
tokens, err = s.a.GetTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(tokens), Equals, 2)
|
|
}
|
|
|
|
func (s *AuthSuite) TestBadTokens(c *C) {
|
|
// empty
|
|
_, err := s.a.ValidateToken("")
|
|
c.Assert(err, NotNil)
|
|
|
|
// garbage
|
|
_, err = s.a.ValidateToken("bla bla")
|
|
c.Assert(err, NotNil)
|
|
|
|
// tampered
|
|
tok, err := s.a.GenerateToken(GenerateTokenRequest{Roles: teleport.Roles{teleport.RoleAuth}})
|
|
c.Assert(err, IsNil)
|
|
|
|
tampered := string(tok[0]+1) + tok[1:]
|
|
_, err = s.a.ValidateToken(tampered)
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (s *AuthSuite) TestBuildRolesInvalid(c *C) {
|
|
// create a connector
|
|
oidcConnector := services.NewOIDCConnector("example", services.OIDCConnectorSpecV2{
|
|
IssuerURL: "https://www.exmaple.com",
|
|
ClientID: "example-client-id",
|
|
ClientSecret: "example-client-secret",
|
|
RedirectURL: "https://localhost:3080/v1/webapi/oidc/callback",
|
|
Display: "sign in with example.com",
|
|
Scope: []string{"foo", "bar"},
|
|
})
|
|
|
|
// create some claims
|
|
var claims = make(jose.Claims)
|
|
claims.Add("roles", "teleport-user")
|
|
claims.Add("email", "foo@example.com")
|
|
claims.Add("nickname", "foo")
|
|
claims.Add("full_name", "foo bar")
|
|
|
|
// try and build roles should be invalid since we have no mappings
|
|
_, err := s.a.buildOIDCRoles(oidcConnector, claims)
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (s *AuthSuite) TestBuildRolesStatic(c *C) {
|
|
// create a connector
|
|
oidcConnector := services.NewOIDCConnector("example", services.OIDCConnectorSpecV2{
|
|
IssuerURL: "https://www.exmaple.com",
|
|
ClientID: "example-client-id",
|
|
ClientSecret: "example-client-secret",
|
|
RedirectURL: "https://localhost:3080/v1/webapi/oidc/callback",
|
|
Display: "sign in with example.com",
|
|
Scope: []string{"foo", "bar"},
|
|
ClaimsToRoles: []services.ClaimMapping{
|
|
services.ClaimMapping{
|
|
Claim: "roles",
|
|
Value: "teleport-user",
|
|
Roles: []string{"user"},
|
|
},
|
|
},
|
|
})
|
|
|
|
// create some claims
|
|
var claims = make(jose.Claims)
|
|
claims.Add("roles", "teleport-user")
|
|
claims.Add("email", "foo@example.com")
|
|
claims.Add("nickname", "foo")
|
|
claims.Add("full_name", "foo bar")
|
|
|
|
// build roles and check that we mapped to "user" role
|
|
roles, err := s.a.buildOIDCRoles(oidcConnector, claims)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(roles, HasLen, 1)
|
|
c.Assert(roles[0], Equals, "user")
|
|
}
|
|
|
|
func (s *AuthSuite) TestValidateACRValues(c *C) {
|
|
|
|
var tests = []struct {
|
|
inIDToken string
|
|
inACRValue string
|
|
inACRProvider string
|
|
outIsValid bool
|
|
}{
|
|
// 0 - default, acr values match
|
|
{
|
|
`
|
|
{
|
|
"acr": "foo",
|
|
"aud": "00000000-0000-0000-0000-000000000000",
|
|
"exp": 1111111111
|
|
}
|
|
`,
|
|
"foo",
|
|
"",
|
|
true,
|
|
},
|
|
// 1 - default, acr values do not match
|
|
{
|
|
`
|
|
{
|
|
"acr": "foo",
|
|
"aud": "00000000-0000-0000-0000-000000000000",
|
|
"exp": 1111111111
|
|
}
|
|
`,
|
|
"bar",
|
|
"",
|
|
false,
|
|
},
|
|
// 2 - netiq, acr values match
|
|
{
|
|
`
|
|
{
|
|
"acr": {
|
|
"values": [
|
|
"foo/bar/baz"
|
|
]
|
|
},
|
|
"aud": "00000000-0000-0000-0000-000000000000",
|
|
"exp": 1111111111
|
|
}
|
|
`,
|
|
"foo/bar/baz",
|
|
"netiq",
|
|
true,
|
|
},
|
|
// 3 - netiq, invalid format
|
|
{
|
|
`
|
|
{
|
|
"acr": {
|
|
"values": "foo/bar/baz"
|
|
},
|
|
"aud": "00000000-0000-0000-0000-000000000000",
|
|
"exp": 1111111111
|
|
}
|
|
`,
|
|
"foo/bar/baz",
|
|
"netiq",
|
|
false,
|
|
},
|
|
// 4 - netiq, invalid value
|
|
{
|
|
`
|
|
{
|
|
"acr": {
|
|
"values": [
|
|
"foo/bar/baz/qux"
|
|
]
|
|
},
|
|
"aud": "00000000-0000-0000-0000-000000000000",
|
|
"exp": 1111111111
|
|
}
|
|
`,
|
|
"foo/bar/baz",
|
|
"netiq",
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
comment := Commentf("Test %v", i)
|
|
|
|
var claims jose.Claims
|
|
err := json.Unmarshal([]byte(tt.inIDToken), &claims)
|
|
c.Assert(err, IsNil, comment)
|
|
|
|
err = s.a.validateACRValues(tt.inACRValue, tt.inACRProvider, claims)
|
|
if tt.outIsValid {
|
|
c.Assert(err, IsNil, comment)
|
|
} else {
|
|
c.Assert(err, NotNil, comment)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *AuthSuite) TestUpdateConfig(c *C) {
|
|
cn, err := s.a.GetClusterName()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(cn.GetClusterName(), Equals, "me.localhost")
|
|
st, err := s.a.GetStaticTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(st.GetStaticTokens(), DeepEquals, []services.ProvisionToken{})
|
|
|
|
// try and set cluster name, this should fail because you can only set the
|
|
// cluster name once
|
|
clusterName, err := services.NewClusterName(services.ClusterNameSpecV2{
|
|
ClusterName: "foo.localhost",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
// use same backend but start a new auth server with different config.
|
|
authConfig := &InitConfig{
|
|
ClusterName: clusterName,
|
|
Backend: s.bk,
|
|
Authority: authority.New(),
|
|
SkipPeriodicOperations: true,
|
|
}
|
|
authServer, err := NewAuthServer(authConfig)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = authServer.SetClusterName(clusterName)
|
|
c.Assert(err, NotNil)
|
|
// try and set static tokens, this should be successful because the last
|
|
// one to upsert tokens wins
|
|
staticTokens, err := services.NewStaticTokens(services.StaticTokensSpecV2{
|
|
StaticTokens: []services.ProvisionTokenV1{services.ProvisionTokenV1{
|
|
Token: "bar",
|
|
Roles: teleport.Roles{teleport.Role("baz")},
|
|
}},
|
|
})
|
|
c.Assert(err, IsNil)
|
|
err = authServer.SetStaticTokens(staticTokens)
|
|
c.Assert(err, IsNil)
|
|
|
|
// check first auth server and make sure it returns the correct values
|
|
// (original cluster name, new static tokens)
|
|
cn, err = s.a.GetClusterName()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(cn.GetClusterName(), Equals, "me.localhost")
|
|
st, err = s.a.GetStaticTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(st.GetStaticTokens(), DeepEquals, services.ProvisionTokensFromV1([]services.ProvisionTokenV1{services.ProvisionTokenV1{
|
|
Token: "bar",
|
|
Roles: teleport.Roles{teleport.Role("baz")},
|
|
}}))
|
|
|
|
// check second auth server and make sure it also has the correct values
|
|
// new static tokens
|
|
st, err = authServer.GetStaticTokens()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(st.GetStaticTokens(), DeepEquals, services.ProvisionTokensFromV1([]services.ProvisionTokenV1{services.ProvisionTokenV1{
|
|
Token: "bar",
|
|
Roles: teleport.Roles{teleport.Role("baz")},
|
|
}}))
|
|
}
|
|
|
|
func (s *AuthSuite) TestUpdateByWithContext(c *C) {
|
|
ctx := withUpdateBy(context.TODO(), "some-user")
|
|
updatedBy, err := getUpdateBy(ctx)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(updatedBy, Equals, "some-user")
|
|
|
|
// trigger error
|
|
ctx = withUpdateBy(context.TODO(), "")
|
|
updatedBy, err = getUpdateBy(ctx)
|
|
c.Assert(trace.IsBadParameter(err), Equals, true)
|
|
c.Assert(err, ErrorMatches, `missing value "updated_by"`)
|
|
c.Assert(updatedBy, Equals, "")
|
|
}
|
|
|
|
func (s *AuthSuite) TestCreateAndUpdateUser(c *C) {
|
|
s.a.IAuditLog = s.mockedAuditLog
|
|
user, err := services.NewUser("some-user")
|
|
c.Assert(err, IsNil)
|
|
|
|
// test create user
|
|
s.mockedAuditLog.MockEmitAuditEvent = func(event events.Event, fields events.EventFields) error {
|
|
c.Assert(event.Code, Equals, events.UserCreateCode)
|
|
c.Assert(fields[events.EventUser], Equals, "some-auth-user")
|
|
return nil
|
|
}
|
|
|
|
// trigger error
|
|
err = s.a.CreateUser(context.TODO(), user)
|
|
c.Assert(err, ErrorMatches, `created by is not set for new user "some-user"`)
|
|
|
|
// happy path
|
|
user.SetCreatedBy(services.CreatedBy{
|
|
User: services.UserRef{Name: "some-auth-user"},
|
|
})
|
|
err = s.a.CreateUser(context.TODO(), user)
|
|
c.Assert(err, IsNil)
|
|
|
|
// test update user
|
|
s.mockedAuditLog.MockEmitAuditEvent = func(event events.Event, fields events.EventFields) error {
|
|
c.Assert(event.Code, Equals, events.UserUpdateCode)
|
|
c.Assert(fields[events.EventUser], Equals, "some-context-user")
|
|
return nil
|
|
}
|
|
ctx := withUpdateBy(context.TODO(), "some-context-user")
|
|
c.Assert(ctx, NotNil)
|
|
err = s.a.UpdateUser(ctx, user)
|
|
c.Assert(err, IsNil)
|
|
}
|