Last active
August 16, 2016 00:54
-
-
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 )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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