Skip to content

Commit

Permalink
Add login.gov example; sort links alphabetically
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewzah committed Feb 12, 2020
1 parent bb8916b commit b2f29be
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 89 deletions.
55 changes: 31 additions & 24 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/markbates/goth/providers/lastfm"
"github.com/markbates/goth/providers/line"
"github.com/markbates/goth/providers/linkedin"
"github.com/markbates/goth/providers/logingov"
"github.com/markbates/goth/providers/meetup"
"github.com/markbates/goth/providers/microsoftonline"
"github.com/markbates/goth/providers/naver"
Expand Down Expand Up @@ -138,8 +139,17 @@ func main() {
goth.UseProviders(openidConnect)
}

logingov, _ := logingov.New(os.Getenv("LOGINGOV_ISSUER_ID"), os.Getenv("LOGINGOV_REDIRECT_URI"), os.Getenv("LOGINGOV_AUTODISCOVERY_URL"))
if logingov != nil {
goth.UseProviders(logingov)
}

m := make(map[string]string)
m["amazon"] = "Amazon"
m["apple"] = "Apple"
m["auth0"] = "Auth0"
m["azuread"] = "Azure AD"
m["battlenet"] = "Battlenet"
m["bitbucket"] = "Bitbucket"
m["box"] = "Box"
m["dailymotion"] = "Dailymotion"
Expand All @@ -155,41 +165,38 @@ func main() {
m["gitlab"] = "Gitlab"
m["google"] = "Google"
m["gplus"] = "Google Plus"
m["shopify"] = "Shopify"
m["soundcloud"] = "SoundCloud"
m["spotify"] = "Spotify"
m["steam"] = "Steam"
m["stripe"] = "Stripe"
m["twitch"] = "Twitch"
m["uber"] = "Uber"
m["wepay"] = "Wepay"
m["yahoo"] = "Yahoo"
m["yammer"] = "Yammer"
m["heroku"] = "Heroku"
m["instagram"] = "Instagram"
m["intercom"] = "Intercom"
m["lastfm"] = "Last FM"
m["linkedin"] = "Linkedin"
m["line"] = "LINE"
m["onedrive"] = "Onedrive"
m["azuread"] = "Azure AD"
m["linkedin"] = "Linkedin"
m["login.gov"] = "login.gov"
m["meetup"] = "Meetup.com"
m["microsoftonline"] = "Microsoft Online"
m["battlenet"] = "Battlenet"
m["naver"] = "Naver"
m["nextcloud"] = "NextCloud"
m["onedrive"] = "Onedrive"
m["openid-connect"] = "OpenID Connect"
m["paypal"] = "Paypal"
m["twitter"] = "Twitter"
m["salesforce"] = "Salesforce"
m["typetalk"] = "Typetalk"
m["seatalk"] = "SeaTalk"
m["shopify"] = "Shopify"
m["slack"] = "Slack"
m["meetup"] = "Meetup.com"
m["auth0"] = "Auth0"
m["openid-connect"] = "OpenID Connect"
m["xero"] = "Xero"
m["soundcloud"] = "SoundCloud"
m["spotify"] = "Spotify"
m["steam"] = "Steam"
m["stripe"] = "Stripe"
m["twitch"] = "Twitch"
m["twitter"] = "Twitter"
m["typetalk"] = "Typetalk"
m["uber"] = "Uber"
m["vk"] = "VK"
m["naver"] = "Naver"
m["wepay"] = "Wepay"
m["xero"] = "Xero"
m["yahoo"] = "Yahoo"
m["yammer"] = "Yammer"
m["yandex"] = "Yandex"
m["nextcloud"] = "NextCloud"
m["seatalk"] = "SeaTalk"
m["apple"] = "Apple"

var keys []string
for k := range m {
Expand Down
101 changes: 75 additions & 26 deletions providers/logingov/logingov.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ package logingov

import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
b64 "encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"os"
"strings"
"time"

Expand Down Expand Up @@ -42,15 +45,15 @@ const (
)

// These vars are necessary for login.gov auth to work.
const ResponseType string = "code"

// These default to the login.gov sandbox values
// * See the getEnv fn below.
// AcrValues: Only accepts LOA1 or LAO3 urls.
// AcrValues: Accepts /ial/1 or /ial/2, OR /loa/1/ or /loa/3/
// * See https://developers.login.gov/oidc/#authorization
// * Currently only /loa/1 and /ial/1 work, as per the gsa-tts slack.
// I can't test /loa/3 or /ial/2 because my account is only /loa/1.
var (
acrValues = getEnv("LOGINGOV_ACR_VALUES", "http://idmanagement.gov/ns/assurance/loa/1")
responseType = "code"
Emails = strings.Split(os.Getenv("LOGINGOV_APPROVED_EMAILS"), ",")
AcrValues = "http://idmanagement.gov/ns/assurance/loa/1"
ApprovedEmails = []string{}
)

type OpenIdConfig struct {
Expand All @@ -71,13 +74,15 @@ type Address struct {

// Provider is the implementation of `goth.Provider` for accessing login.gov.
type Provider struct {
IssuerId string
CallbackUrl string
HTTPClient *http.Client
providerName string
cfg *oauth2.Config
openIdCfg *OpenIdConfig
codeVerifier string
IssuerId string
CallbackUrl string
HTTPClient *http.Client
providerName string
cfg *oauth2.Config
openIdCfg *OpenIdConfig
codeVerifier string
AcrValues string
ApprovedEmails []string

UuidClaims []string
EmailClaims []string
Expand All @@ -90,13 +95,21 @@ type Provider struct {
AddressClaims []string
}

// New creates a new login.gov provider and sets up important connection details.
// You should always call `logingov.New` to get a new provider. Never try to
// create one manually.
func New(issuerId, callbackUrl, discoveryUrl string, scopes ...string) (*Provider, error) {
return NewCustomisedURL(issuerId, callbackUrl, discoveryUrl, AcrValues, ApprovedEmails, scopes...)
}

// New creates a new login.gov provider and sets up important connection details.
// You should always call `logingov.New` or `logingov.NewCustomisedURL` to get a new
// provider. Never try to create one manually.
func NewCustomisedURL(
issuerId, callbackUrl, discoveryUrl, acrValues string,
approvedEmails []string, scopes ...string) (*Provider, error) {
p := &Provider{
IssuerId: issuerId,
CallbackUrl: callbackUrl,
IssuerId: issuerId,
CallbackUrl: callbackUrl,
AcrValues: acrValues,
ApprovedEmails: approvedEmails,

UuidClaims: []string{UuidClaim},
EmailClaims: []string{EmailClaim},
Expand Down Expand Up @@ -156,12 +169,12 @@ func (p *Provider) BeginAuth(state string) (goth.Session, error) {
}

opts := []oauth2.AuthCodeOption{
oauth2.SetAuthURLParam("acr_values", acrValues),
oauth2.SetAuthURLParam("acr_values", p.AcrValues),
oauth2.SetAuthURLParam("code_challenge", codeChallenge),
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
oauth2.SetAuthURLParam("nonce", nonce),
oauth2.SetAuthURLParam("redirect_uri", p.CallbackUrl),
oauth2.SetAuthURLParam("response_type", responseType),
oauth2.SetAuthURLParam("response_type", ResponseType),
}
return &Session{
AuthURL: p.cfg.AuthCodeURL(state, opts...),
Expand Down Expand Up @@ -211,19 +224,25 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
if err != nil {
return goth.User{}, err
}

// block access if email isn't approved
if len(p.ApprovedEmails) > 0 {
if !contains(p.ApprovedEmails, user.Email) {
return goth.User{}, errors.New("This email is not on the approved access list.")
}
}

return user, err

}

func (p *Provider) userFromClaims(claims map[string]interface{}, user *goth.User) {
if acrValues == "http://idmanagement.gov/ns/assurance/loa/3" {
if p.AcrValues == "http://idmanagement.gov/ns/assurance/loa/3" {
user.Email = getClaimValue(claims, p.EmailClaims)
user.RawData["uuid"] = getClaimValue(claims, p.UuidClaims)
} else {
user.Email = getClaimValue(claims, p.EmailClaims)
}

// required
// email is a required value
user.Email = getClaimValue(claims, p.EmailClaims)
}

Expand Down Expand Up @@ -291,7 +310,7 @@ func newConfig(provider *Provider, scopes []string) *oauth2.Config {
Scopes: []string{},
}

// "email" is the only available scope for LOA1
// "email" is the only available scope for IAL1 / LOA1
// See https://developers.login.gov/attributes/
if len(scopes) > 0 {
for _, scope := range scopes {
Expand Down Expand Up @@ -432,3 +451,33 @@ func getOpenIdConfig(p *Provider, openIDAutoDiscoveryURL string) (*OpenIdConfig,

return openIdConfig, nil
}

func randomHex(n int) (string, error) {
bytes := make([]byte, n)

if _, err := rand.Read(bytes); err != nil {
return "", err
}

return hex.EncodeToString(bytes), nil
}

func genCodeChallenge(length int) (string, string, error) {
code, err := randomHex(length)
if err != nil {
return "", "", err
}

sum := sha256.Sum256([]byte(code))

return code, b64.StdEncoding.EncodeToString(sum[:]), nil
}

func contains(a []string, x string) bool {
for _, n := range a {
if x == n {
return true
}
}
return false
}
39 changes: 0 additions & 39 deletions providers/logingov/utils.go

This file was deleted.

0 comments on commit b2f29be

Please sign in to comment.