http_example_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package jwt_test
  2. // Example HTTP auth using asymmetric crypto/RSA keys
  3. // This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b
  4. import (
  5. "bytes"
  6. "crypto/rsa"
  7. "fmt"
  8. "github.com/dgrijalva/jwt-go"
  9. "github.com/dgrijalva/jwt-go/request"
  10. "io"
  11. "io/ioutil"
  12. "log"
  13. "net"
  14. "net/http"
  15. "net/url"
  16. "strings"
  17. "time"
  18. )
  19. // location of the files used for signing and verification
  20. const (
  21. privKeyPath = "test/sample_key" // openssl genrsa -out app.rsa keysize
  22. pubKeyPath = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
  23. )
  24. var (
  25. verifyKey *rsa.PublicKey
  26. signKey *rsa.PrivateKey
  27. serverPort int
  28. // storing sample username/password pairs
  29. // don't do this on a real server
  30. users = map[string]string{
  31. "test": "known",
  32. }
  33. )
  34. // read the key files before starting http handlers
  35. func init() {
  36. signBytes, err := ioutil.ReadFile(privKeyPath)
  37. fatal(err)
  38. signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
  39. fatal(err)
  40. verifyBytes, err := ioutil.ReadFile(pubKeyPath)
  41. fatal(err)
  42. verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
  43. fatal(err)
  44. http.HandleFunc("/authenticate", authHandler)
  45. http.HandleFunc("/restricted", restrictedHandler)
  46. // Setup listener
  47. listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
  48. serverPort = listener.Addr().(*net.TCPAddr).Port
  49. log.Println("Listening...")
  50. go func() {
  51. fatal(http.Serve(listener, nil))
  52. }()
  53. }
  54. var start func()
  55. func fatal(err error) {
  56. if err != nil {
  57. log.Fatal(err)
  58. }
  59. }
  60. // Define some custom types were going to use within our tokens
  61. type CustomerInfo struct {
  62. Name string
  63. Kind string
  64. }
  65. type CustomClaimsExample struct {
  66. *jwt.StandardClaims
  67. TokenType string
  68. CustomerInfo
  69. }
  70. func Example_getTokenViaHTTP() {
  71. // See func authHandler for an example auth handler that produces a token
  72. res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
  73. "user": {"test"},
  74. "pass": {"known"},
  75. })
  76. if err != nil {
  77. fatal(err)
  78. }
  79. if res.StatusCode != 200 {
  80. fmt.Println("Unexpected status code", res.StatusCode)
  81. }
  82. // Read the token out of the response body
  83. buf := new(bytes.Buffer)
  84. io.Copy(buf, res.Body)
  85. res.Body.Close()
  86. tokenString := strings.TrimSpace(buf.String())
  87. // Parse the token
  88. token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
  89. // since we only use the one private key to sign the tokens,
  90. // we also only use its public counter part to verify
  91. return verifyKey, nil
  92. })
  93. fatal(err)
  94. claims := token.Claims.(*CustomClaimsExample)
  95. fmt.Println(claims.CustomerInfo.Name)
  96. //Output: test
  97. }
  98. func Example_useTokenViaHTTP() {
  99. // Make a sample token
  100. // In a real world situation, this token will have been acquired from
  101. // some other API call (see Example_getTokenViaHTTP)
  102. token, err := createToken("foo")
  103. fatal(err)
  104. // Make request. See func restrictedHandler for example request processor
  105. req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
  106. fatal(err)
  107. req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
  108. res, err := http.DefaultClient.Do(req)
  109. fatal(err)
  110. // Read the response body
  111. buf := new(bytes.Buffer)
  112. io.Copy(buf, res.Body)
  113. res.Body.Close()
  114. fmt.Println(buf.String())
  115. // Output: Welcome, foo
  116. }
  117. func createToken(user string) (string, error) {
  118. // create a signer for rsa 256
  119. t := jwt.New(jwt.GetSigningMethod("RS256"))
  120. // set our claims
  121. t.Claims = &CustomClaimsExample{
  122. &jwt.StandardClaims{
  123. // set the expire time
  124. // see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
  125. ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
  126. },
  127. "level1",
  128. CustomerInfo{user, "human"},
  129. }
  130. // Creat token string
  131. return t.SignedString(signKey)
  132. }
  133. // reads the form values, checks them and creates the token
  134. func authHandler(w http.ResponseWriter, r *http.Request) {
  135. // make sure its post
  136. if r.Method != "POST" {
  137. w.WriteHeader(http.StatusBadRequest)
  138. fmt.Fprintln(w, "No POST", r.Method)
  139. return
  140. }
  141. user := r.FormValue("user")
  142. pass := r.FormValue("pass")
  143. log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)
  144. // check values
  145. if user != "test" || pass != "known" {
  146. w.WriteHeader(http.StatusForbidden)
  147. fmt.Fprintln(w, "Wrong info")
  148. return
  149. }
  150. tokenString, err := createToken(user)
  151. if err != nil {
  152. w.WriteHeader(http.StatusInternalServerError)
  153. fmt.Fprintln(w, "Sorry, error while Signing Token!")
  154. log.Printf("Token Signing error: %v\n", err)
  155. return
  156. }
  157. w.Header().Set("Content-Type", "application/jwt")
  158. w.WriteHeader(http.StatusOK)
  159. fmt.Fprintln(w, tokenString)
  160. }
  161. // only accessible with a valid token
  162. func restrictedHandler(w http.ResponseWriter, r *http.Request) {
  163. // Get token from request
  164. token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
  165. // since we only use the one private key to sign the tokens,
  166. // we also only use its public counter part to verify
  167. return verifyKey, nil
  168. })
  169. // If the token is missing or invalid, return error
  170. if err != nil {
  171. w.WriteHeader(http.StatusUnauthorized)
  172. fmt.Fprintln(w, "Invalid token:", err)
  173. return
  174. }
  175. // Token is valid
  176. fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
  177. return
  178. }