@@ -13,7 +13,9 @@ import (
1313
1414 jwt "github.com/dgrijalva/jwt-go"
1515 "github.com/libp2p/go-libp2p-core/crypto"
16+ "github.com/libp2p/go-libp2p-core/peer"
1617 "github.com/qri-io/qfs"
18+ "github.com/qri-io/qri/auth/key"
1719 "github.com/qri-io/qri/profile"
1820)
1921
@@ -36,6 +38,7 @@ type Token = jwt.Token
3638// Claims is a JWT Claims object
3739type Claims struct {
3840 * jwt.StandardClaims
41+ // TODO(b5): this needs to be replaced with a profileID
3942 Username string `json:"username"`
4043}
4144
@@ -44,6 +47,83 @@ func Parse(tokenString string, tokens Source) (*Token, error) {
4447 return jwt .Parse (tokenString , tokens .VerificationKey )
4548}
4649
50+ // NewPrivKeyAuthToken creates a JWT token string suitable for making requests
51+ // authenticated as the given private key
52+ func NewPrivKeyAuthToken (pk crypto.PrivKey , ttl time.Duration ) (string , error ) {
53+ signingMethod , err := jwtSigningMethod (pk )
54+ if err != nil {
55+ return "" , err
56+ }
57+
58+ t := jwt .New (signingMethod )
59+
60+ id , err := key .IDFromPrivKey (pk )
61+ if err != nil {
62+ return "" , err
63+ }
64+
65+ rawPrivBytes , err := pk .Raw ()
66+ if err != nil {
67+ return "" , err
68+ }
69+ signKey , err := x509 .ParsePKCS1PrivateKey (rawPrivBytes )
70+ if err != nil {
71+ return "" , err
72+ }
73+
74+ var exp int64
75+ if ttl != time .Duration (0 ) {
76+ exp = Timestamp ().Add (ttl ).In (time .UTC ).Unix ()
77+ }
78+
79+ // set our claims
80+ t .Claims = & Claims {
81+ StandardClaims : & jwt.StandardClaims {
82+ Issuer : id ,
83+ Subject : id ,
84+ // set the expire time
85+ // see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
86+ ExpiresAt : exp ,
87+ },
88+ }
89+
90+ // Creat token string
91+ return t .SignedString (signKey )
92+ }
93+
94+ // ParseAuthToken will parse, validate and return a token
95+ func ParseAuthToken (tokenString string , keystore key.Store ) (* Token , error ) {
96+ claims := & Claims {}
97+ return jwt .ParseWithClaims (tokenString , claims , func (t * Token ) (interface {}, error ) {
98+ pid , err := peer .Decode (claims .Issuer )
99+ if err != nil {
100+ return nil , err
101+ }
102+ pubKey := keystore .PubKey (pid )
103+ if pubKey == nil {
104+ for _ , pid := range keystore .IDsWithKeys () {
105+ fmt .Printf ("key %s has a pid\n " , pid )
106+ }
107+ return nil , fmt .Errorf ("cannot verify key. missing public key for id %s" , claims .Issuer )
108+ }
109+ rawPubBytes , err := pubKey .Raw ()
110+ if err != nil {
111+ return nil , err
112+ }
113+
114+ verifyKeyiface , err := x509 .ParsePKIXPublicKey (rawPubBytes )
115+ if err != nil {
116+ return nil , err
117+ }
118+
119+ verifyKey , ok := verifyKeyiface .(* rsa.PublicKey )
120+ if ! ok {
121+ return nil , fmt .Errorf ("public key is not an RSA key. got type: %T" , verifyKeyiface )
122+ }
123+ return verifyKey , nil
124+ })
125+ }
126+
47127// Source creates tokens, and provides a verification key for all tokens
48128// it creates
49129//
@@ -69,17 +149,11 @@ var _ Source = (*pkSource)(nil)
69149// NewPrivKeySource creates an authentication interface backed by a single
70150// private key. Intended for a node running as remote, or providing a public API
71151func NewPrivKeySource (privKey crypto.PrivKey ) (Source , error ) {
72- methodStr := ""
73- keyType := privKey .Type ().String ()
74- switch keyType {
75- case "RSA" :
76- methodStr = "RS256"
77- default :
78- return nil , fmt .Errorf ("unsupported key type for token creation: %q" , keyType )
152+ signingMethod , err := jwtSigningMethod (privKey )
153+ if err != nil {
154+ return nil , err
79155 }
80156
81- signingMethod := jwt .GetSigningMethod (methodStr )
82-
83157 rawPrivBytes , err := privKey .Raw ()
84158 if err != nil {
85159 return nil , err
@@ -304,3 +378,13 @@ func (st *qfsStore) save(ctx context.Context) error {
304378 st .path = path
305379 return nil
306380}
381+
382+ func jwtSigningMethod (pk crypto.PrivKey ) (jwt.SigningMethod , error ) {
383+ keyType := pk .Type ().String ()
384+ switch keyType {
385+ case "RSA" :
386+ return jwt .GetSigningMethod ("RS256" ), nil
387+ default :
388+ return nil , fmt .Errorf ("unsupported key type for token creation: %q" , keyType )
389+ }
390+ }
0 commit comments