options.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright 2018 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package auth
  15. import (
  16. "crypto/ecdsa"
  17. "crypto/rsa"
  18. "fmt"
  19. "io/ioutil"
  20. "time"
  21. jwt "github.com/dgrijalva/jwt-go"
  22. )
  23. const (
  24. optSignMethod = "sign-method"
  25. optPublicKey = "pub-key"
  26. optPrivateKey = "priv-key"
  27. optTTL = "ttl"
  28. )
  29. var knownOptions = map[string]bool{
  30. optSignMethod: true,
  31. optPublicKey: true,
  32. optPrivateKey: true,
  33. optTTL: true,
  34. }
  35. var (
  36. // DefaultTTL will be used when a 'ttl' is not specified
  37. DefaultTTL = 5 * time.Minute
  38. )
  39. type jwtOptions struct {
  40. SignMethod jwt.SigningMethod
  41. PublicKey []byte
  42. PrivateKey []byte
  43. TTL time.Duration
  44. }
  45. // ParseWithDefaults will load options from the specified map or set defaults where appropriate
  46. func (opts *jwtOptions) ParseWithDefaults(optMap map[string]string) error {
  47. if opts.TTL == 0 && optMap[optTTL] == "" {
  48. opts.TTL = DefaultTTL
  49. }
  50. return opts.Parse(optMap)
  51. }
  52. // Parse will load options from the specified map
  53. func (opts *jwtOptions) Parse(optMap map[string]string) error {
  54. var err error
  55. if ttl := optMap[optTTL]; ttl != "" {
  56. opts.TTL, err = time.ParseDuration(ttl)
  57. if err != nil {
  58. return err
  59. }
  60. }
  61. if file := optMap[optPublicKey]; file != "" {
  62. opts.PublicKey, err = ioutil.ReadFile(file)
  63. if err != nil {
  64. return err
  65. }
  66. }
  67. if file := optMap[optPrivateKey]; file != "" {
  68. opts.PrivateKey, err = ioutil.ReadFile(file)
  69. if err != nil {
  70. return err
  71. }
  72. }
  73. // signing method is a required field
  74. method := optMap[optSignMethod]
  75. opts.SignMethod = jwt.GetSigningMethod(method)
  76. if opts.SignMethod == nil {
  77. return ErrInvalidAuthMethod
  78. }
  79. return nil
  80. }
  81. // Key will parse and return the appropriately typed key for the selected signature method
  82. func (opts *jwtOptions) Key() (interface{}, error) {
  83. switch opts.SignMethod.(type) {
  84. case *jwt.SigningMethodRSA, *jwt.SigningMethodRSAPSS:
  85. return opts.rsaKey()
  86. case *jwt.SigningMethodECDSA:
  87. return opts.ecKey()
  88. case *jwt.SigningMethodHMAC:
  89. return opts.hmacKey()
  90. default:
  91. return nil, fmt.Errorf("unsupported signing method: %T", opts.SignMethod)
  92. }
  93. }
  94. func (opts *jwtOptions) hmacKey() (interface{}, error) {
  95. if len(opts.PrivateKey) == 0 {
  96. return nil, ErrMissingKey
  97. }
  98. return opts.PrivateKey, nil
  99. }
  100. func (opts *jwtOptions) rsaKey() (interface{}, error) {
  101. var (
  102. priv *rsa.PrivateKey
  103. pub *rsa.PublicKey
  104. err error
  105. )
  106. if len(opts.PrivateKey) > 0 {
  107. priv, err = jwt.ParseRSAPrivateKeyFromPEM(opts.PrivateKey)
  108. if err != nil {
  109. return nil, err
  110. }
  111. }
  112. if len(opts.PublicKey) > 0 {
  113. pub, err = jwt.ParseRSAPublicKeyFromPEM(opts.PublicKey)
  114. if err != nil {
  115. return nil, err
  116. }
  117. }
  118. if priv == nil {
  119. if pub == nil {
  120. // Neither key given
  121. return nil, ErrMissingKey
  122. }
  123. // Public key only, can verify tokens
  124. return pub, nil
  125. }
  126. // both keys provided, make sure they match
  127. if pub != nil && pub.E != priv.E && pub.N.Cmp(priv.N) != 0 {
  128. return nil, ErrKeyMismatch
  129. }
  130. return priv, nil
  131. }
  132. func (opts *jwtOptions) ecKey() (interface{}, error) {
  133. var (
  134. priv *ecdsa.PrivateKey
  135. pub *ecdsa.PublicKey
  136. err error
  137. )
  138. if len(opts.PrivateKey) > 0 {
  139. priv, err = jwt.ParseECPrivateKeyFromPEM(opts.PrivateKey)
  140. if err != nil {
  141. return nil, err
  142. }
  143. }
  144. if len(opts.PublicKey) > 0 {
  145. pub, err = jwt.ParseECPublicKeyFromPEM(opts.PublicKey)
  146. if err != nil {
  147. return nil, err
  148. }
  149. }
  150. if priv == nil {
  151. if pub == nil {
  152. // Neither key given
  153. return nil, ErrMissingKey
  154. }
  155. // Public key only, can verify tokens
  156. return pub, nil
  157. }
  158. // both keys provided, make sure they match
  159. if pub != nil && pub.Curve != priv.Curve &&
  160. pub.X.Cmp(priv.X) != 0 && pub.Y.Cmp(priv.Y) != 0 {
  161. return nil, ErrKeyMismatch
  162. }
  163. return priv, nil
  164. }