Skip to content

Instantly share code, notes, and snippets.

@seanhagen
Last active August 16, 2016 00:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanhagen/8ce1332b3ab35c4a0143ca1afd19d912 to your computer and use it in GitHub Desktop.
Save seanhagen/8ce1332b3ab35c4a0143ca1afd19d912 to your computer and use it in GitHub Desktop.
Storing this here for use later ( don't want to clutter up a repo with an entirely commented out file )
package app
// Routes to handle validating user login against the auth app.
// Currently doesn't do anything because the Auth app isn't up yet. Need to get
// that deployed so this can be fleshed out.
import (
"fmt"
"github.com/KloudKtrl/internal/database"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/context"
"github.com/julienschmidt/httprouter"
"github.com/unrolled/render"
"golang.org/x/oauth2"
"io"
"log"
"net/http"
)
// Routes defined:
// POST /oauth2
// GET /oauth2callback
type (
GoogleDiscovery struct {
Issuer string
AuthEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserInfoEndpoint string `json:"userinfo_endpoint"`
RevocationEndpoint string `json:"revocation_endpoint"`
JWKS string `json:"jwks_uri"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSingingAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
ScopesSupported []string `json:"scopes_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
ClaimsSupported []string `json:"claims_supported"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
}
GoogCert struct {
KTY string `json:"kty"`
ALG string `json:"alg"`
USE string `json:"use"`
KID string `json:"kid"`
N string `json:"n"`
E string `json:"e"`
}
GoogleSigningCerts struct {
Keys []GoogCert
}
)
func (c GoogleSigningCerts) getKeyById(id string) string {
for _, v := range c.Keys {
if v.KID == id {
return v.N
}
}
return ""
}
func buildState(r *http.Request, params httprouter.Params) string {
return "this-should-be-the-team-id-or-something"
}
var discoveryDocURI = "https://accounts.google.com/.well-known/openid-configuration"
func fetchGoogleDiscoveryDocument() (GoogleDiscovery, error) {
var r GoogleDiscovery
err := fetchJSON(discoveryDocURI, &r)
return r, err
}
func fetchGoogleSigningCert(url string) (GoogleSigningCerts, error) {
var r GoogleSigningCerts
err := fetchJSON(url, &r)
return r, err
}
func getOauth2Route(db *db.Database) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
oauth := context.Get(r, "oauth").(*oauth2.Config)
url := oauth.AuthCodeURL(buildState(r, params))
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
}
func getOauth2CallbackRoute(db *db.Database) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
oauth := context.Get(r, "oauth").(*oauth2.Config)
code := r.URL.Query().Get("code")
token, err := oauth.Exchange(oauth2.NoContext, code)
if err != nil {
e := fmt.Sprintf("Unable to validate Google OAuth2 token; %#v", err.Error())
log.Printf(e)
w.WriteHeader(http.StatusInternalServerError)
io.WriteString(w, e)
return
}
jtok, err := jwt.Parse(token.Extra("id_token").(string), func(token *jwt.Token) (interface{}, error) {
discovery, _ := fetchGoogleDiscoveryDocument()
certs, _ := fetchGoogleSigningCert(discovery.JWKS)
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"].(string))
}
return certs.getKeyById(token.Header["kid"].(string)), nil
})
if err != nil {
e := fmt.Sprintf("Unable to validate key: %#v", err.Error())
log.Printf(e)
w.WriteHeader(http.StatusInternalServerError)
io.WriteString(w, e)
}
type retval struct {
Token interface{}
JWT interface{}
}
rts := retval{
Token: token,
JWT: jtok,
}
ren := context.Get(r, "render").(*render.Render)
ren.JSON(w, http.StatusOK, rts)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment