Don't assume private key to be available on a traditional file system.

This commit is contained in:
Burcu Dogan 2014-08-16 18:04:02 -07:00
parent ee77246177
commit 03a41b25d4
3 changed files with 38 additions and 37 deletions

View File

@ -53,10 +53,15 @@ func Example_config() {
func Example_jWTConfig() { func Example_jWTConfig() {
conf, err := oauth2.NewJWTConfig(&oauth2.JWTOptions{ conf, err := oauth2.NewJWTConfig(&oauth2.JWTOptions{
Email: "xxx@developer.gserviceaccount.com", Email: "xxx@developer.gserviceaccount.com",
// The path to the pem file. If you have a p12 file instead, you // The contents of your RSA private key or your PEM file
// that contains a private key.
// If you have a p12 file instead, you
// can use `openssl` to export the private key into a pem file. // can use `openssl` to export the private key into a pem file.
//
// $ openssl pkcs12 -in key.p12 -out key.pem -nodes // $ openssl pkcs12 -in key.p12 -out key.pem -nodes
PEMFilename: "/path/to/pem/file.pem", //
// It only supports PEM containers with no passphrase.
PrivateKey: []byte("PRIVATE KEY CONTENTS"),
Scopes: []string{"SCOPE1", "SCOPE2"}, Scopes: []string{"SCOPE1", "SCOPE2"},
}, },
"https://provider.com/o/oauth2/token") "https://provider.com/o/oauth2/token")

View File

@ -49,10 +49,15 @@ func Example_serviceAccounts() {
// Developer Console (https://console.developers.google.com). // Developer Console (https://console.developers.google.com).
config, err := google.NewServiceAccountConfig(&oauth2.JWTOptions{ config, err := google.NewServiceAccountConfig(&oauth2.JWTOptions{
Email: "xxx@developer.gserviceaccount.com", Email: "xxx@developer.gserviceaccount.com",
// PEMFilename. If you have a p12 file instead, you // The contents of your RSA private key or your PEM file
// can use `openssl` to export the private key into a pem file. // that contains a private key.
// If you have a p12 file instead, you
// can use `openssl` to export the private key into a PEM file.
//
// $ openssl pkcs12 -in key.p12 -out key.pem -nodes // $ openssl pkcs12 -in key.p12 -out key.pem -nodes
PEMFilename: "/path/to/pem/file.pem", //
// Supports only PEM containers without a passphrase.
PrivateKey: []byte("PRIVATE KEY CONTENTS"),
Scopes: []string{ Scopes: []string{
"https://www.googleapis.com/auth/bigquery", "https://www.googleapis.com/auth/bigquery",
}, },

47
jwt.go
View File

@ -10,7 +10,6 @@ import (
"encoding/json" "encoding/json"
"encoding/pem" "encoding/pem"
"errors" "errors"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@ -31,17 +30,15 @@ type JWTOptions struct {
// the configured OAuth provider. // the configured OAuth provider.
Email string `json:"email"` Email string `json:"email"`
// PrivateKey is an RSA private key to sign JWS payloads. // PrivateKey contains the contents of an RSA private key or the
PrivateKey *rsa.PrivateKey `json:"-"` // contents of a PEM file that contains a private key. The provided
// private key is used to sign JWT payloads.
// The path to a PEM container that includes your private key. // PEM containers with a passphrase are not supported.
// If PrivateKey is set, this field is ignored. // Use the following command to convert a PKCS 12 file into a PEM.
// //
// If you have a p12 file instead, you
// can use `openssl` to export the private key into a PEM file.
// $ openssl pkcs12 -in key.p12 -out key.pem -nodes // $ openssl pkcs12 -in key.p12 -out key.pem -nodes
// PEM file should contain your private key. //
PEMFilename string `json:"pemfilename"` PrivateKey []byte `json:"-"`
// Scopes identify the level of access being requested. // Scopes identify the level of access being requested.
Scopes []string `json:"scopes"` Scopes []string `json:"scopes"`
@ -54,14 +51,7 @@ func NewJWTConfig(opts *JWTOptions, aud string) (*JWTConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if opts.PrivateKey != nil { parsedKey, err := parseKey(opts.PrivateKey)
return &JWTConfig{opts: opts, aud: audURL, key: opts.PrivateKey}, nil
}
contents, err := ioutil.ReadFile(opts.PEMFilename)
if err != nil {
return nil, err
}
parsedKey, err := parsePemKey(contents)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -155,25 +145,26 @@ func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) {
return return
} }
// parsePemKey parses the pem file to extract the private key. // parseKey converts the binary contents of a private key file
// It returns an error if private key is not provided or the // to an *rsa.PrivateKey. It detects whether the private key is in a
// provided key is invalid. // PEM container or not. If so, it extracts the the private key
func parsePemKey(key []byte) (*rsa.PrivateKey, error) { // from PEM container before conversion. It only supports PEM
invalidPrivateKeyErr := errors.New("oauth2: private key is invalid") // containers with no passphrase.
func parseKey(key []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(key) block, _ := pem.Decode(key)
if block == nil { if block != nil {
return nil, invalidPrivateKeyErr key = block.Bytes
} }
parsedKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) parsedKey, err := x509.ParsePKCS8PrivateKey(key)
if err != nil { if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
parsed, ok := parsedKey.(*rsa.PrivateKey) parsed, ok := parsedKey.(*rsa.PrivateKey)
if !ok { if !ok {
return nil, invalidPrivateKeyErr return nil, errors.New("oauth2: private key is invalid")
} }
return parsed, nil return parsed, nil
} }