Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion api/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"time"

jwt "github.com/dgrijalva/jwt-go"
"github.com/gobuffalo/uuid"
"github.com/netlify/gotrue/api/provider"
"github.com/netlify/gotrue/models"
"github.com/netlify/gotrue/storage"
"github.com/gobuffalo/uuid"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -173,10 +173,15 @@ func (a *API) internalExternalProviderCallback(w http.ResponseWriter, r *http.Re
}
}

if userData.AppMetadata != nil {
user.UpdateAppMetaData(tx, userData.AppMetadata)
}

token, terr = a.issueRefreshToken(ctx, tx, user)
if terr != nil {
return oauthError("server_error", terr.Error())
}

return nil
})
if err != nil {
Expand Down Expand Up @@ -276,6 +281,8 @@ func (a *API) Provider(ctx context.Context, name string) (provider.Provider, err
return provider.NewGoogleProvider(config.External.Google)
case "facebook":
return provider.NewFacebookProvider(config.External.Facebook)
case "netlify":
return provider.NewNetlifyProvider(config.External.Netlify)
case "saml":
return provider.NewSamlProvider(config.External.Saml, a.db, getInstanceID(ctx))
default:
Expand Down
52 changes: 52 additions & 0 deletions api/external_oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ package api

import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"net/http"

"github.com/netlify/gotrue/api/provider"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
)

// loadOAuthState parses the `state` query parameter as a JWS payload,
Expand Down Expand Up @@ -54,9 +63,52 @@ func (a *API) oAuthCallback(ctx context.Context, r *http.Request, providerType s
return nil, internalServerError("Error getting user email from external provider").WithInternalError(err)
}

config := a.getConfig(ctx)
if config.External.TokenEncryptionKey != "" {
cipher, err := encryptToken(config.External.TokenEncryptionKey, tok)
if err != nil {
log.WithError(err).Warn("Unable to encrypt oauth token for JWT payload")
} else {
if userData.AppMetadata == nil {
userData.AppMetadata = make(map[string]interface{})
}
key := fmt.Sprintf("%s_token", providerType)
userData.AppMetadata[key] = cipher
}
}

return userData, nil
}

func encryptToken(pemKey string, token *oauth2.Token) (string, error) {
// read pubkey
block, _ := pem.Decode([]byte(pemKey))
if block == nil || block.Type != "PUBLIC KEY" {
return "", errors.New("failed to decode PEM block containing public key")
}

parsedKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return "", err
}

pubKey, ok := parsedKey.(*rsa.PublicKey)
if !ok {
return "", errors.New("Unable to parse RSA public key, generating a temp one")
}

secretMessage := []byte(token.AccessToken)
label := []byte("token")

ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, secretMessage, label)
if err != nil {
return "", err
}

base64Cipher := base64.StdEncoding.EncodeToString(ciphertext)
return base64Cipher, nil
}

func (a *API) OAuthProvider(ctx context.Context, name string) (provider.OAuthProvider, error) {
providerCandidate, err := a.Provider(ctx, name)
if err != nil {
Expand Down
69 changes: 69 additions & 0 deletions api/provider/netlify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package provider

import (
"context"
"errors"

"github.com/netlify/gotrue/conf"
"golang.org/x/oauth2"
)

var netlifyOauthEndpoint = oauth2.Endpoint{
AuthURL: "https://app.netlify.com/authorize",
TokenURL: "https://api.netlify.com/oauth/token",
}

const netlifyUserEndpoint = "https://api.netlify.com/api/v1/user"

type netlifyProvider struct {
*oauth2.Config
}

type netlifyUser struct {
AvatarURL string `json:"avatar_url,omitempty"`
Email string `json:"email,omitempty"`
FullName string `json:"full_name,omitempty"`
ID string `json:"id,omitempty"`
}

// NewNetlifyProvider provides a configured provider for logging in with Netlify
func NewNetlifyProvider(ext conf.OAuthProviderConfiguration) (OAuthProvider, error) {
if err := ext.Validate(); err != nil {
return nil, err
}

return &netlifyProvider{
&oauth2.Config{
ClientID: ext.ClientID,
ClientSecret: ext.Secret,
Endpoint: netlifyOauthEndpoint,
RedirectURL: ext.RedirectURI,
},
}, nil
}

func (n netlifyProvider) GetOAuthToken(code string) (*oauth2.Token, error) {
return n.Exchange(oauth2.NoContext, code)
}

func (n netlifyProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) {
var u netlifyUser
if err := makeRequest(ctx, tok, n.Config, netlifyUserEndpoint, &u); err != nil {
return nil, err
}

data := &UserProvidedData{
Email: u.Email,
Verified: true,
Metadata: map[string]string{
nameKey: u.FullName,
avatarURLKey: u.AvatarURL,
},
}

if data.Email == "" {
return nil, errors.New("Unable to find email with Netlify provider")
}

return data, nil
}
7 changes: 4 additions & 3 deletions api/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ const (
)

type UserProvidedData struct {
Email string
Verified bool
Metadata map[string]string
Email string
Verified bool
Metadata map[string]string
AppMetadata map[string]interface{}
}

// Provider is an interface for interacting with external account providers
Expand Down
2 changes: 2 additions & 0 deletions api/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type ProviderSettings struct {
GitLab bool `json:"gitlab"`
Google bool `json:"google"`
Facebook bool `json:"facebook"`
Netlify bool `json:"netlify"`
Email bool `json:"email"`
SAML bool `json:"saml"`
}
Expand All @@ -33,6 +34,7 @@ func (a *API) Settings(w http.ResponseWriter, r *http.Request) error {
GitLab: config.External.Gitlab.Enabled,
Google: config.External.Google.Enabled,
Facebook: config.External.Facebook.Enabled,
Netlify: config.External.Netlify.Enabled,
Email: !config.External.Email.Disabled,
SAML: config.External.Saml.Enabled,
},
Expand Down
3 changes: 3 additions & 0 deletions conf/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ type ProviderConfiguration struct {
Gitlab OAuthProviderConfiguration `json:"gitlab"`
Google OAuthProviderConfiguration `json:"google"`
Facebook OAuthProviderConfiguration `json:"facebook"`
Netlify OAuthProviderConfiguration `json:"netlify"`
Email EmailProviderConfiguration `json:"email"`
Saml SamlProviderConfiguration `json:"saml"`
RedirectURL string `json:"redirect_url"`

TokenEncryptionKey string `json:"token_encryption_key" split_words:"true"`
}

type SMTPConfiguration struct {
Expand Down
36 changes: 8 additions & 28 deletions go.mod
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -12,76 +12,56 @@ require (
github.com/bugsnag/bugsnag-go v1.3.0 // indirect
github.com/bugsnag/panicwrap v0.0.0-20170829152406-dd8df9a3778a // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9 // indirect
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
github.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4 // indirect
github.com/go-chi/chi v3.1.4+incompatible
github.com/go-kit/kit v0.8.0 // indirect
github.com/go-logfmt/logfmt v0.4.0 // indirect
github.com/go-sql-driver/mysql v1.4.1
github.com/go-stack/stack v1.8.0 // indirect
github.com/gobuffalo/buffalo-plugins v1.9.4 // indirect
github.com/gobuffalo/gogen v0.1.1 // indirect
github.com/gobuffalo/nulls v0.0.0-20190305142546-85f3c9250d87 // indirect
github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3 // indirect
github.com/gobuffalo/plush v3.7.32+incompatible // indirect
github.com/gobuffalo/pop v4.11.0+incompatible
github.com/gobuffalo/tags v2.0.15+incompatible // indirect
github.com/gobuffalo/uuid v2.0.5+incompatible
github.com/gobuffalo/x v0.0.0-20181110221217-14085ca3e1a9 // indirect
github.com/gogo/protobuf v0.0.0-20171109181519-616a82ed12d7 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
github.com/hashicorp/raft v1.0.0 // indirect
github.com/imdario/mergo v0.0.0-20160216103600-3e95a51e0639
github.com/joho/godotenv v1.3.0
github.com/jonboulle/clockwork v0.0.0-20180716110948-e7c6d408fd5c // indirect
github.com/jtolds/gls v4.2.1+incompatible // indirect
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect
github.com/juju/loggo v0.0.0-20180524022052-584905176618 // indirect
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 // indirect
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
github.com/kelseyhightower/envconfig v1.3.0
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 // indirect
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
github.com/nats-io/gnatsd v1.3.0 // indirect
github.com/nats-io/go-nats v1.3.0 // indirect
github.com/nats-io/go-nats-streaming v0.3.4 // indirect
github.com/nats-io/nats-streaming-server v0.11.2 // indirect
github.com/nats-io/nuid v0.0.0-20170303150224-3cf34f9fca4e // indirect
github.com/netlify/mailme v0.0.0-20170821082834-c4a76ce443c1
github.com/netlify/netlify-commons v0.7.7
github.com/netlify/netlify-commons v0.14.0
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect
github.com/pelletier/go-buffruneio v0.1.0 // indirect
github.com/pkg/errors v0.8.1
github.com/pkg/sftp v0.0.0-20160908100035-8197a2e58073 // indirect
github.com/rs/cors v0.0.0-20170608165155-8dd4211afb5d
github.com/russellhaering/gosaml2 v0.3.1
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7
github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35
github.com/shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d // indirect
github.com/signalfx/com_signalfx_metrics_protobuf v0.0.0-20170330202426-93e507b42f43 // indirect
github.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083 // indirect
github.com/signalfx/golib v1.0.0 // indirect
github.com/sirupsen/logrus v1.4.1
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
github.com/spf13/afero v1.2.0 // indirect
github.com/spf13/cobra v0.0.3
github.com/streadway/amqp v0.0.0-20170707203015-2cbfe40c9341 // indirect
github.com/spf13/viper v1.3.1 // indirect
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect
golang.org/x/net v0.0.0-20190514140710-3ec191127204 // indirect
golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95
golang.org/x/sys v0.0.0-20190515190549-87c872767d25 // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20190515235946-4f9510c6a12d // indirect
google.golang.org/api v0.0.0-20170821230356-dd6bdadc5852 // indirect
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/logfmt.v0 v0.3.0 // indirect
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
gopkg.in/stack.v1 v1.6.0 // indirect
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect
)
Loading