109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
package oidc
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/coreos/go-oidc/jose"
|
|
)
|
|
|
|
// RequestTokenExtractor funcs extract a raw encoded token from a request.
|
|
type RequestTokenExtractor func(r *http.Request) (string, error)
|
|
|
|
// ExtractBearerToken is a RequestTokenExtractor which extracts a bearer token from a request's
|
|
// Authorization header.
|
|
func ExtractBearerToken(r *http.Request) (string, error) {
|
|
ah := r.Header.Get("Authorization")
|
|
if ah == "" {
|
|
return "", errors.New("missing Authorization header")
|
|
}
|
|
|
|
if len(ah) <= 6 || strings.ToUpper(ah[0:6]) != "BEARER" {
|
|
return "", errors.New("should be a bearer token")
|
|
}
|
|
|
|
val := ah[7:]
|
|
if len(val) == 0 {
|
|
return "", errors.New("bearer token is empty")
|
|
}
|
|
|
|
return val, nil
|
|
}
|
|
|
|
// CookieTokenExtractor returns a RequestTokenExtractor which extracts a token from the named cookie in a request.
|
|
func CookieTokenExtractor(cookieName string) RequestTokenExtractor {
|
|
return func(r *http.Request) (string, error) {
|
|
ck, err := r.Cookie(cookieName)
|
|
if err != nil {
|
|
return "", fmt.Errorf("token cookie not found in request: %v", err)
|
|
}
|
|
|
|
if ck.Value == "" {
|
|
return "", errors.New("token cookie found but is empty")
|
|
}
|
|
|
|
return ck.Value, nil
|
|
}
|
|
}
|
|
|
|
func NewClaims(iss, sub string, aud interface{}, iat, exp time.Time) jose.Claims {
|
|
return jose.Claims{
|
|
// required
|
|
"iss": iss,
|
|
"sub": sub,
|
|
"aud": aud,
|
|
"iat": iat.Unix(),
|
|
"exp": exp.Unix(),
|
|
}
|
|
}
|
|
|
|
func GenClientID(hostport string) (string, error) {
|
|
b, err := randBytes(32)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var host string
|
|
if strings.Contains(hostport, ":") {
|
|
host, _, err = net.SplitHostPort(hostport)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
} else {
|
|
host = hostport
|
|
}
|
|
|
|
return fmt.Sprintf("%s@%s", base64.URLEncoding.EncodeToString(b), host), nil
|
|
}
|
|
|
|
func randBytes(n int) ([]byte, error) {
|
|
b := make([]byte, n)
|
|
got, err := rand.Read(b)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if n != got {
|
|
return nil, errors.New("unable to generate enough random data")
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// urlEqual checks two urls for equality using only the host and path portions.
|
|
func urlEqual(url1, url2 string) bool {
|
|
u1, err := url.Parse(url1)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
u2, err := url.Parse(url2)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return strings.ToLower(u1.Host+u1.Path) == strings.ToLower(u2.Host+u2.Path)
|
|
}
|