-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
user: claims and parsing for invitations
- Loading branch information
Joe Bowers
committed
Nov 11, 2015
1 parent
ca9227f
commit 468c1b8
Showing
4 changed files
with
204 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package user | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"time" | ||
|
||
"github.com/coreos/go-oidc/jose" | ||
"github.com/coreos/go-oidc/key" | ||
"github.com/coreos/go-oidc/oidc" | ||
) | ||
|
||
func NewInvitation(user User, password Password, issuer url.URL, clientID string, callback url.URL, expires time.Duration) Invitation { | ||
claims := oidc.NewClaims(issuer.String(), user.ID, clientID, clock.Now(), clock.Now().Add(expires)) | ||
claims.Add(ClaimPasswordResetPassword, string(password)) | ||
claims.Add(ClaimEmailVerificationEmail, user.Email) | ||
claims.Add(ClaimInvitationCallback, callback.String()) | ||
return Invitation{claims} | ||
} | ||
|
||
type Invitation struct { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
Claims jose.Claims | ||
} | ||
|
||
func ParseAndVerifyInvitationToken(token string, issuer url.URL, keys []key.PublicKey) (Invitation, error) { | ||
tokenClaims, err := parseAndVerifyTokenClaims(token, issuer, keys) | ||
if err != nil { | ||
return Invitation{}, err | ||
} | ||
|
||
cb, ok, err := tokenClaims.Claims.StringClaim(ClaimInvitationCallback) | ||
if err != nil { | ||
return Invitation{}, err | ||
} | ||
if !ok || cb == "" { | ||
return Invitation{}, fmt.Errorf("no %q claim", ClaimInvitationCallback) | ||
} | ||
if _, err := url.Parse(cb); err != nil { | ||
return Invitation{}, fmt.Errorf("callback URL not parseable: %v", cb) | ||
} | ||
|
||
pw, ok, err := tokenClaims.Claims.StringClaim(ClaimPasswordResetPassword) | ||
if err != nil { | ||
return Invitation{}, err | ||
} | ||
if !ok || pw == "" { | ||
return Invitation{}, fmt.Errorf("no %q claim", ClaimPasswordResetPassword) | ||
} | ||
|
||
email, ok, err := tokenClaims.Claims.StringClaim(ClaimEmailVerificationEmail) | ||
if err != nil { | ||
return Invitation{}, err | ||
} | ||
if !ok || email == "" { | ||
return Invitation{}, fmt.Errorf("no %q claim", ClaimEmailVerificationEmail) | ||
} | ||
|
||
return Invitation{tokenClaims.Claims}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package user | ||
|
||
import ( | ||
"net/url" | ||
"testing" | ||
"time" | ||
|
||
"github.com/kylelemons/godebug/pretty" | ||
|
||
"github.com/coreos/go-oidc/jose" | ||
"github.com/coreos/go-oidc/key" | ||
) | ||
|
||
func TestInvitationParseAndVerify(t *testing.T) { | ||
issuer, _ := url.Parse("http://example.com") | ||
notIssuer, _ := url.Parse("http://other.com") | ||
client := "myclient" | ||
user := User{ID: "1234", Email: "[email protected]"} | ||
callback, _ := url.Parse("http://client.example.com") | ||
expires := time.Hour * 3 | ||
password := Password("Halloween is the best holiday") | ||
privKey, _ := key.GeneratePrivateKey() | ||
signer := privKey.Signer() | ||
publicKeys := []key.PublicKey{*key.NewPublicKey(privKey.JWK())} | ||
|
||
goodInvitation := NewInvitation(user, password, *issuer, client, *callback, expires) | ||
This comment has been minimized.
Sorry, something went wrong.
bobbyrullo
Contributor
|
||
goodNoCB := NewInvitation(user, password, *issuer, client, *callback, expires) | ||
expired := NewInvitation(user, password, *issuer, client, *callback, -expires) | ||
wrongIssuer := NewInvitation(user, password, *notIssuer, client, *callback, expires) | ||
noSub := NewInvitation(User{Email: "[email protected]"}, password, *issuer, client, *callback, expires) | ||
noEmail := NewInvitation(User{ID: "JONNY_NO_EMAIL"}, password, *issuer, client, *callback, expires) | ||
noPassword := NewInvitation(user, Password(""), *issuer, client, *callback, expires) | ||
noClient := NewInvitation(user, password, *issuer, "", *callback, expires) | ||
noClientNoCB := NewInvitation(user, password, *issuer, "", url.URL{}, expires) | ||
|
||
tests := []struct { | ||
invite Invitation | ||
wantErr bool | ||
signer jose.Signer | ||
}{ | ||
{ | ||
invite: goodInvitation, | ||
signer: signer, | ||
wantErr: false, | ||
}, | ||
{ | ||
invite: goodNoCB, | ||
signer: signer, | ||
wantErr: false, | ||
}, | ||
{ | ||
invite: expired, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: wrongIssuer, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: noSub, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: noEmail, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: noPassword, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: noClient, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
{ | ||
invite: noClientNoCB, | ||
signer: signer, | ||
wantErr: true, | ||
}, | ||
} | ||
|
||
for i, tt := range tests { | ||
jwt, err := jose.NewSignedJWT(tt.invite.Claims, tt.signer) | ||
if err != nil { | ||
t.Fatalf("case %d: failed to generate JWT, error: %v", i, err) | ||
} | ||
token := jwt.Encode() | ||
|
||
parsed, err := ParseAndVerifyInvitationToken(token, *issuer, publicKeys) | ||
|
||
if tt.wantErr { | ||
if err == nil { | ||
t.Errorf("case %d: want no-nil error, got nil", i) | ||
} | ||
continue | ||
} | ||
|
||
if err != nil { | ||
t.Errorf("case %d: unexpected error: %v", i, err) | ||
continue | ||
} | ||
|
||
if diff := pretty.Compare(tt.invite, parsed); diff != "" { | ||
t.Errorf("case %d: Compare(want, got): %v", i, diff) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typo: addwress