Skip to content

Commit

Permalink
example: add working example app & cli tool
Browse files Browse the repository at this point in the history
  • Loading branch information
bcwaldon committed Jul 8, 2015
1 parent 965c438 commit 5f791bb
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin
/gopath
8 changes: 7 additions & 1 deletion build
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#!/bin/bash -e

go build ./...
GOBUILD="go build -a -installsuffix netgo -ldflags '-s'"

echo "building bin/oidc-example-app..."
${GOBUILD} -o bin/oidc-example-app github.com/coreos/go-oidc/example/app
echo "building bin/oidc-example-cli..."
${GOBUILD} -o bin/oidc-example-cli github.com/coreos/go-oidc/example/cli
echo "done"
162 changes: 162 additions & 0 deletions example/app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"net/url"
"os"
"time"

"github.com/coreos/go-oidc/oidc"
)

var (
pathCallback = "/oauth2callback"
defaultListenHost = "127.0.0.1:5555"
)

func main() {
log.SetOutput(os.Stderr)

fs := flag.NewFlagSet("oidc-example-app", flag.ExitOnError)
listen := fs.String("listen", defaultListenHost, "serve traffic on this address (<host>:<port>)")
redirectURL := fs.String("redirect-url", fmt.Sprintf("http://%s%s", defaultListenHost, pathCallback), "")
clientID := fs.String("client-id", "", "")
clientSecret := fs.String("client-secret", "", "")
discovery := fs.String("discovery", "https://accounts.google.com", "")

if err := fs.Parse(os.Args[1:]); err != nil {
log.Fatalf("failed parsing flags: %v", err)
}

if *clientID == "" {
log.Fatal("--client-id must be set")
}

if *clientSecret == "" {
log.Fatal("--client-secret must be set")
}

_, _, err := net.SplitHostPort(*listen)
if err != nil {
log.Fatalf("unable to parse host:port from --listen flag: %v", err)
}

cc := oidc.ClientCredentials{
ID: *clientID,
Secret: *clientSecret,
}

log.Printf("fetching provider config from %s...", *discovery)

var cfg oidc.ProviderConfig
for {
cfg, err = oidc.FetchProviderConfig(http.DefaultClient, *discovery)
if err == nil {
break
}

sleep := 3 * time.Second
log.Printf("failed fetching provider config, trying again in %v: %v", sleep, err)
time.Sleep(sleep)
}

log.Printf("fetched provider config from %s: %#v", *discovery, cfg)

ccfg := oidc.ClientConfig{
ProviderConfig: cfg,
Credentials: cc,
RedirectURL: *redirectURL,
}

client, err := oidc.NewClient(ccfg)
if err != nil {
log.Fatalf("unable to create Client: %v", err)
}

client.SyncProviderConfig(*discovery)

redirectURLParsed, err := url.Parse(*redirectURL)
if err != nil {
log.Fatalf("unable to parse url from --redirect-url flag: %v", err)
}
hdlr := NewClientHandler(client, *redirectURLParsed)
httpsrv := &http.Server{
Addr: fmt.Sprintf(*listen),
Handler: hdlr,
}

log.Printf("binding to %s...", httpsrv.Addr)
log.Fatal(httpsrv.ListenAndServe())
}

func NewClientHandler(c *oidc.Client, cbURL url.URL) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", handleIndex)
mux.HandleFunc("/login", handleLoginFunc(c))
mux.HandleFunc(pathCallback, handleCallbackFunc(c))
return mux
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("<a href='/login'>login</a>"))
}

func handleLoginFunc(c *oidc.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
oac, err := c.OAuthClient()
if err != nil {
panic("unable to proceed")
}

u, err := url.Parse(oac.AuthCodeURL("", "", ""))
if err != nil {
panic("unable to proceed")
}
http.Redirect(w, r, u.String(), http.StatusFound)
}
}

func handleCallbackFunc(c *oidc.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
if code == "" {
writeError(w, http.StatusBadRequest, "code query param must be set")
return
}

tok, err := c.ExchangeAuthCode(code)
if err != nil {
writeError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err))
return
}

claims, err := tok.Claims()
if err != nil {
writeError(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err))
return
}

s := fmt.Sprintf("claims: %v", claims)
w.Write([]byte(s))
}
}

func writeError(w http.ResponseWriter, code int, msg string) {
e := struct {
Error string `json:"error"`
}{
Error: msg,
}
b, err := json.Marshal(e)
if err != nil {
log.Printf("Failed marshaling %#v to JSON: %v", e, err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
w.Write(b)
}
83 changes: 83 additions & 0 deletions example/cli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package main

import (
"flag"
"fmt"
"net/http"
"os"
"time"

"github.com/coreos/go-oidc/oidc"
)

func main() {
fs := flag.NewFlagSet("oidc-example-cli", flag.ExitOnError)
clientID := fs.String("client-id", "", "")
clientSecret := fs.String("client-secret", "", "")
discovery := fs.String("discovery", "https://accounts.google.com", "")

if err := fs.Parse(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}

if *clientID == "" {
fmt.Println("--client-id must be set")
os.Exit(2)
}

if *clientSecret == "" {
fmt.Println("--client-secret must be set")
os.Exit(2)
}

cc := oidc.ClientCredentials{
ID: *clientID,
Secret: *clientSecret,
}

log.Printf("fetching provider config from %s...", *discovery)

// NOTE: A real CLI would cache this config, or provide it via flags/config file.
var cfg oidc.ProviderConfig
var err error
for {
cfg, err = oidc.FetchProviderConfig(http.DefaultClient, *discovery)
if err == nil {
break
}

sleep := 1 * time.Second
fmt.Printf("failed fetching provider config, trying again in %v: %v\n", sleep, err)
time.Sleep(sleep)
}

fmt.Printf("fetched provider config from %s: %#v\n\n", *discovery, cfg)

ccfg := oidc.ClientConfig{
ProviderConfig: cfg,
Credentials: cc,
}

client, err := oidc.NewClient(ccfg)
if err != nil {
fmt.Printf("unable to create Client: %v\n", err)
os.Exit(1)
}

tok, err := client.ClientCredsToken([]string{"openid"})
if err != nil {
fmt.Printf("unable to verify auth code with issuer: %v\n", err)
os.Exit(1)
}

fmt.Printf("got jwt: %v\n\n", tok.Encode())

claims, err := tok.Claims()
if err != nil {
fmt.Printf("unable to construct claims: %v\n", err)
os.Exit(1)
}

fmt.Printf("got claims %#v...\n", claims)
}

0 comments on commit 5f791bb

Please sign in to comment.