Skip to content

Commit

Permalink
ClientCredentials flow in UserAPI
Browse files Browse the repository at this point in the history
Fixes #528
  • Loading branch information
Adrián López Gómez committed Sep 1, 2016
1 parent fa8f98a commit 9b8ab3b
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 83 deletions.
24 changes: 14 additions & 10 deletions cmd/dex-worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func main() {

enableClientRegistration := fs.Bool("enable-client-registration", false, "Allow dynamic registration of clients")

// Client credentials administration
apiUseClientCredentials := fs.Bool("api-use-client-credentials", false, "Forces API to authenticate using client credentials instead of ID token. Clients must be 'admin clients' to use the API.")

noDB := fs.Bool("no-db", false, "manage entities in-process w/o any encryption, used only for single-node testing")

// UI-related:
Expand Down Expand Up @@ -137,16 +140,17 @@ func main() {
}

scfg := server.ServerConfig{
IssuerURL: *issuer,
TemplateDir: *templates,
EmailTemplateDirs: emailTemplateDirs,
EmailFromAddress: *emailFrom,
EmailerConfigFile: *emailConfig,
IssuerName: *issuerName,
IssuerLogoURL: *issuerLogoURL,
EnableRegistration: *enableRegistration,
EnableClientRegistration: *enableClientRegistration,
RegisterOnFirstLogin: *registerOnFirstLogin,
IssuerURL: *issuer,
TemplateDir: *templates,
EmailTemplateDirs: emailTemplateDirs,
EmailFromAddress: *emailFrom,
EmailerConfigFile: *emailConfig,
IssuerName: *issuerName,
IssuerLogoURL: *issuerLogoURL,
EnableRegistration: *enableRegistration,
EnableClientRegistration: *enableClientRegistration,
EnableClientCredentialAccess: *apiUseClientCredentials,
RegisterOnFirstLogin: *registerOnFirstLogin,
}

if *noDB {
Expand Down
187 changes: 177 additions & 10 deletions integration/user_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ var (
userGoodToken = makeUserToken(testIssuerURL,
"ID-1", testClientID, time.Hour*1, testPrivKey)

clientToken = makeClientToken(testIssuerURL,
testClientID, time.Hour*1, testPrivKey)

badClientToken = makeClientToken(testIssuerURL,
userBadClientID, time.Hour*1, testPrivKey)

userBadTokenNotAdmin = makeUserToken(testIssuerURL,
"ID-2", testClientID, time.Hour*1, testPrivKey)

Expand All @@ -97,7 +103,7 @@ var (
"ID-4", testClientID, time.Hour*1, testPrivKey)
)

func makeUserAPITestFixtures() *userAPITestFixtures {
func makeUserAPITestFixtures(clientCredsFlag bool) *userAPITestFixtures {
f := &userAPITestFixtures{}

dbMap, _, _, um := makeUserObjects(userUsers, userPasswords)
Expand Down Expand Up @@ -157,8 +163,8 @@ func makeUserAPITestFixtures() *userAPITestFixtures {
f.emailer = &testEmailer{}
um.Clock = clock

api := api.NewUsersAPI(um, clientManager, refreshRepo, f.emailer, "local")
usrSrv := server.NewUserMgmtServer(api, jwtvFactory, um, clientManager)
api := api.NewUsersAPI(um, clientManager, refreshRepo, f.emailer, "local", clientCredsFlag)
usrSrv := server.NewUserMgmtServer(api, jwtvFactory, um, clientManager, clientCredsFlag)
f.hSrv = httptest.NewServer(usrSrv.HTTPHandler())

f.trans = &tokenHandlerTransport{
Expand All @@ -180,48 +186,89 @@ func TestGetUser(t *testing.T) {
token string

errCode int

clientCredsFlag bool
}{
{
id: "ID-1",

token: userGoodToken,
errCode: 0,
}, {

clientCredsFlag: false,
},
{
id: "ID-1",

token: clientToken,
errCode: 0,

clientCredsFlag: true,
},
{
id: "ID-1",

token: badClientToken,
errCode: http.StatusForbidden,

clientCredsFlag: true,
},
{
id: "ID-1",

token: clientToken,
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
},
{
id: "NOONE",

token: userGoodToken,
errCode: http.StatusNotFound,

clientCredsFlag: false,
}, {
id: "ID-1",

token: userBadTokenNotAdmin,
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
}, {
id: "ID-1",

token: userBadTokenExpired,
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
}, {
id: "ID-1",

token: userBadTokenDisabled,
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
}, {
id: "ID-1",

token: "",
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
}, {
id: "ID-1",

token: "gibberish",
errCode: http.StatusUnauthorized,

clientCredsFlag: false,
},
}

for i, tt := range tests {
func() {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(tt.clientCredsFlag)
f.trans.Token = tt.token

defer f.close()
Expand Down Expand Up @@ -318,7 +365,7 @@ func TestListUsers(t *testing.T) {

for i, tt := range tests {
func() {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(false)
defer f.close()
f.trans.Token = tt.token

Expand Down Expand Up @@ -382,6 +429,8 @@ func TestCreateUser(t *testing.T) {

wantResponse schema.UserCreateResponse
wantCode int

clientCredsFlag bool
}{
{

Expand Down Expand Up @@ -409,6 +458,53 @@ func TestCreateUser(t *testing.T) {
},
},
},
{

req: schema.UserCreateRequest{
User: &schema.User{
Email: "newuser@example.com",
DisplayName: "New User",
EmailVerified: true,
Admin: false,
CreatedAt: clock.Now().Format(time.RFC3339),
},
RedirectURL: testRedirectURL.String(),
},

token: clientToken,

wantResponse: schema.UserCreateResponse{
EmailSent: true,
User: &schema.User{
Email: "newuser@example.com",
DisplayName: "New User",
EmailVerified: true,
Admin: false,
CreatedAt: clock.Now().Format(time.RFC3339),
},
},

clientCredsFlag: true,
},
{

req: schema.UserCreateRequest{
User: &schema.User{
Email: "newuser@example.com",
DisplayName: "New User",
EmailVerified: true,
Admin: false,
CreatedAt: clock.Now().Format(time.RFC3339),
},
RedirectURL: testRedirectURL.String(),
},

token: badClientToken,

wantCode: http.StatusForbidden,

clientCredsFlag: true,
},
{

// Duplicate email
Expand Down Expand Up @@ -488,6 +584,28 @@ func TestCreateUser(t *testing.T) {

wantCode: http.StatusUnauthorized,
},
{

req: schema.UserCreateRequest{
User: &schema.User{
Email: "newuser@example.com",
DisplayName: "New User",
EmailVerified: true,
Admin: false,
CreatedAt: clock.Now().Format(time.RFC3339),
},

RedirectURL: testRedirectURL.String(),
},

// make sure that the endpoint is protected, but don't exhaustively
// try every variation like in TestGetUser
token: clientToken,

wantCode: http.StatusUnauthorized,

clientCredsFlag: false,
},
{
req: schema.UserCreateRequest{
User: &schema.User{
Expand All @@ -507,7 +625,7 @@ func TestCreateUser(t *testing.T) {
}
for i, tt := range tests {
func() {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(tt.clientCredsFlag)
defer f.close()
f.trans.Token = tt.token
f.emailer.cantEmail = tt.cantEmail
Expand Down Expand Up @@ -588,7 +706,7 @@ func TestDisableUser(t *testing.T) {
}

for i, tt := range tests {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(false)

usr, err := f.client.Users.Get(tt.id).Do()
if err != nil {
Expand Down Expand Up @@ -625,7 +743,7 @@ func TestRefreshTokenEndpoints(t *testing.T) {
}

for i, tt := range tests {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(false)
list, err := f.client.RefreshClient.List(tt.userID).Do()
if err != nil {
t.Errorf("case %d: list clients: %v", i, err)
Expand Down Expand Up @@ -666,6 +784,8 @@ func TestResendEmailInvitation(t *testing.T) {

wantResponse schema.ResendEmailInvitationResponse
wantCode int

clientCredsFlag bool
}{
{

Expand All @@ -687,6 +807,36 @@ func TestResendEmailInvitation(t *testing.T) {
RedirectURL: testRedirectURL.String(),
},

userID: "ID-3",
email: "Email-3@example.com",
token: clientToken,

wantResponse: schema.ResendEmailInvitationResponse{
EmailSent: true,
},

clientCredsFlag: true,
},
{

req: schema.ResendEmailInvitationRequest{
RedirectURL: testRedirectURL.String(),
},

userID: "ID-3",
email: "Email-3@example.com",
token: badClientToken,

wantCode: http.StatusForbidden,

clientCredsFlag: true,
},
{

req: schema.ResendEmailInvitationRequest{
RedirectURL: testRedirectURL.String(),
},

userID: "ID-3",
email: "Email-3@example.com",
cantEmail: true,
Expand Down Expand Up @@ -747,6 +897,19 @@ func TestResendEmailInvitation(t *testing.T) {
RedirectURL: testRedirectURL.String(),
},

userID: "ID-3",
email: "Email-3@example.com",
token: clientToken,

wantCode: http.StatusUnauthorized,

clientCredsFlag: false,
},
{
req: schema.ResendEmailInvitationRequest{
RedirectURL: testRedirectURL.String(),
},

userID: "ID-3",
email: "Email-3@example.com",
token: userBadTokenExpired,
Expand Down Expand Up @@ -778,7 +941,7 @@ func TestResendEmailInvitation(t *testing.T) {
}
for i, tt := range tests {
func() {
f := makeUserAPITestFixtures()
f := makeUserAPITestFixtures(tt.clientCredsFlag)
defer f.close()
f.trans.Token = tt.token
f.emailer.cantEmail = tt.cantEmail
Expand Down Expand Up @@ -869,6 +1032,10 @@ func (t *testEmailer) SendInviteEmail(email string, redirectURL url.URL, clientI
return retURL, nil
}

func makeClientToken(issuerURL url.URL, clientID string, expires time.Duration, privKey *key.PrivateKey) string {
return makeUserToken(issuerURL, clientID, clientID, expires, privKey)
}

func makeUserToken(issuerURL url.URL, userID, clientID string, expires time.Duration, privKey *key.PrivateKey) string {

signer := key.NewPrivateKeySet([]*key.PrivateKey{testPrivKey},
Expand Down

0 comments on commit 9b8ab3b

Please sign in to comment.