|
|
@@ -0,0 +1,104 @@ |
|
|
package main |
|
|
|
|
|
import ( |
|
|
"fmt" |
|
|
"io/ioutil" |
|
|
"log" |
|
|
"net/http" |
|
|
"os" |
|
|
|
|
|
"golang.org/x/oauth2" |
|
|
"golang.org/x/oauth2/google" |
|
|
|
|
|
"google.golang.org/appengine" |
|
|
) |
|
|
|
|
|
// TODO: This must be randomized per request |
|
|
const todoBadStateImplementation = "9bd752171ba8fd0590fe5c26c5f03c23" |
|
|
|
|
|
var oauthConfig = oauth2.Config{ |
|
|
ClientID: "TODO", |
|
|
ClientSecret: "TODO", |
|
|
Endpoint: google.Endpoint, |
|
|
Scopes: []string{"email"}, |
|
|
RedirectURL: "http://localhost:8080/oauth_callback", |
|
|
} |
|
|
|
|
|
func init() { |
|
|
http.HandleFunc("/", handler) |
|
|
http.HandleFunc("/start", startOauth) |
|
|
http.HandleFunc("/oauth_callback", oauthCallback) |
|
|
} |
|
|
|
|
|
func handler(w http.ResponseWriter, r *http.Request) { |
|
|
w.Header().Set("Content-Type", "text/plain;charset=utf-8") |
|
|
|
|
|
ctx := appengine.NewContext(r) |
|
|
fmt.Fprintln(w, "REQUEST ID:", appengine.RequestID(ctx)) |
|
|
fmt.Fprintln(w) |
|
|
|
|
|
fmt.Fprintln(w, "HEADERS:") |
|
|
for k, values := range r.Header { |
|
|
fmt.Fprintln(w, k, ":") |
|
|
for _, s := range values { |
|
|
fmt.Fprintln(w, " ", s) |
|
|
} |
|
|
} |
|
|
fmt.Fprintln(w) |
|
|
|
|
|
fmt.Fprintln(w, "ENVIRONMENT:") |
|
|
for _, s := range os.Environ() { |
|
|
fmt.Fprintln(w, s) |
|
|
} |
|
|
} |
|
|
|
|
|
func startOauth(w http.ResponseWriter, r *http.Request) { |
|
|
url := oauthConfig.AuthCodeURL(todoBadStateImplementation) |
|
|
log.Println("startOauth: redirecting to", url) |
|
|
http.Redirect(w, r, url, http.StatusFound) |
|
|
} |
|
|
|
|
|
func oauthCallback(w http.ResponseWriter, r *http.Request) { |
|
|
errorString := r.FormValue("error") |
|
|
if errorString != "" { |
|
|
panic(errorString) |
|
|
} |
|
|
|
|
|
stateString := r.FormValue("state") |
|
|
if stateString != todoBadStateImplementation { |
|
|
panic("state does not match") |
|
|
} |
|
|
|
|
|
// things look like they might be valid! Let's get the token |
|
|
code := r.FormValue("code") |
|
|
ctx := appengine.NewContext(r) |
|
|
token, err := oauthConfig.Exchange(ctx, code) |
|
|
if err != nil { |
|
|
panic(err) |
|
|
} |
|
|
|
|
|
// it worked! get the tokeninfo |
|
|
log.Printf("access_token: %s refresh_token: %s", token.AccessToken, token.RefreshToken) |
|
|
tokeninfoUrl := "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=" + token.AccessToken |
|
|
log.Println("URL: ", tokeninfoUrl) |
|
|
resp, err := http.Get(tokeninfoUrl) |
|
|
if err != nil { |
|
|
panic(err) |
|
|
} |
|
|
data, err := ioutil.ReadAll(resp.Body) |
|
|
err2 := resp.Body.Close() |
|
|
if err != nil { |
|
|
panic(err) |
|
|
} |
|
|
if err2 != nil { |
|
|
panic(err2) |
|
|
} |
|
|
|
|
|
w.Header().Set("Content-Type", "text/plain;charset=utf-8") |
|
|
fmt.Fprintln(w, "Tokeninfo:") |
|
|
w.Write(data) |
|
|
} |
|
|
|
|
|
func main() { |
|
|
appengine.Main() |
|
|
} |