Skip to content

Instantly share code, notes, and snippets.

@rhafer
Created June 1, 2023 13:50
Show Gist options
  • Save rhafer/8f94d55d39332589ba0cb80fd6c1b2ce to your computer and use it in GitHub Desktop.
Save rhafer/8f94d55d39332589ba0cb80fd6c1b2ce to your computer and use it in GitHub Desktop.
lico implicit scope reproducer
clients:
- id: works
name: ownCloud Web app
trusted: true
implicit_scopes:
- LibgreGraph.UUID
secret: ""
redirect_uris:
- http://127.0.0.1
- http://localhost
origins: []
application_type: native
- id: broken
name: ownCloud Web app
implicit_scopes:
- LibgreGraph.UUID
secret: ""
redirect_uris:
- http://127.0.0.1
- http://localhost
origins: []
application_type: native
/*
This is an example application to demonstrate querying the user info endpoint. (adapted for use with lico)
Adapt the provider URL on line 62 to you needs.
*/
package main
import (
"crypto/rand"
"crypto/tls"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
var (
clientID = os.Getenv("CLIENT_ID")
clientSecret = os.Getenv("CLIENT_SECRET")
)
func randString(nByte int) (string, error) {
b := make([]byte, nByte)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(b), nil
}
func setCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) {
c := &http.Cookie{
Name: name,
Value: value,
MaxAge: int(time.Hour.Seconds()),
Secure: r.TLS != nil,
HttpOnly: true,
}
http.SetCookie(w, c)
}
func main() {
ctx := context.Background()
var oidcHTTPClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true,
},
DisableKeepAlives: true,
},
Timeout: time.Second * 10,
}
ctx = oidc.ClientContext(ctx, oidcHTTPClient)
provider, err := oidc.NewProvider(ctx, "https://ocis.owncloud.test")
if err != nil {
log.Fatal(err)
}
config := oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Endpoint: provider.Endpoint(),
RedirectURL: "http://127.0.0.1:5556/auth/google/callback",
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
state, err := randString(16)
if err != nil {
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
setCallbackCookie(w, r, "state", state)
//http.Redirect(w, r, config.AuthCodeURL(state, oauth2.ApprovalForce), http.StatusFound)
http.Redirect(w, r, config.AuthCodeURL(state), http.StatusFound)
})
http.HandleFunc("/auth/google/callback", func(w http.ResponseWriter, r *http.Request) {
state, err := r.Cookie("state")
if err != nil {
http.Error(w, "state not found", http.StatusBadRequest)
return
}
if r.URL.Query().Get("state") != state.Value {
http.Error(w, "state did not match", http.StatusBadRequest)
return
}
oauth2Token, err := config.Exchange(ctx, r.URL.Query().Get("code"))
if err != nil {
http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
return
}
userInfo, err := provider.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
if err != nil {
http.Error(w, "Failed to get userinfo: "+err.Error(), http.StatusInternalServerError)
return
}
var claims map[string]interface{}
err = userInfo.Claims(&claims)
fmt.Printf("Error %v\n", err)
resp := struct {
OAuth2Token *oauth2.Token
UserInfo map[string]interface{}
}{oauth2Token, claims}
data, err := json.MarshalIndent(resp, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(data)
})
log.Printf("listening on http://%s/", "127.0.0.1:5556")
log.Fatal(http.ListenAndServe("127.0.0.1:5556", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment