dex/server/auth_middleware.go
Evan Cordell a418e1c4e7 client: add client manager
adds a client manager to handle business logic, leaving the repo
for basic crud operations. Also adds client to the test script
2016-05-19 16:20:12 -07:00

124 lines
2.7 KiB
Go

package server
import (
"errors"
"fmt"
"net/http"
"github.com/coreos/dex/client/manager"
"github.com/coreos/dex/pkg/log"
"github.com/coreos/go-oidc/jose"
"github.com/coreos/go-oidc/key"
"github.com/coreos/go-oidc/oidc"
)
type clientTokenMiddleware struct {
issuerURL string
ciManager *manager.ClientManager
keysFunc func() ([]key.PublicKey, error)
next http.Handler
}
func (c *clientTokenMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
respondError := func() {
writeAPIError(w, http.StatusUnauthorized, newAPIError(errorAccessDenied, "missing or invalid token"))
}
if c.keysFunc == nil {
log.Errorf("Misconfigured clientTokenMiddleware, keysFunc is not set")
respondError()
return
}
if c.ciManager == nil {
log.Errorf("Misconfigured clientTokenMiddleware, ClientManager is not set")
respondError()
return
}
rawToken, err := oidc.ExtractBearerToken(r)
if err != nil {
log.Errorf("Failed to extract token from request: %v", err)
respondError()
return
}
jwt, err := jose.ParseJWT(rawToken)
if err != nil {
log.Errorf("Failed to parse JWT from token: %v", err)
respondError()
return
}
keys, err := c.keysFunc()
if err != nil {
log.Errorf("Failed to get keys: %v", err)
writeAPIError(w, http.StatusUnauthorized, newAPIError(errorAccessDenied, ""))
respondError()
return
}
if len(keys) == 0 {
log.Error("No keys available for verification in client token middleware")
writeAPIError(w, http.StatusUnauthorized, newAPIError(errorAccessDenied, ""))
respondError()
return
}
ok, err := oidc.VerifySignature(jwt, keys)
if err != nil {
log.Errorf("Failed to verify signature: %v", err)
respondError()
return
}
if !ok {
log.Info("Invalid token")
respondError()
return
}
clientID, err := oidc.VerifyClientClaims(jwt, c.issuerURL)
if err != nil {
log.Errorf("Failed to verify JWT claims: %v", err)
respondError()
return
}
md, err := c.ciManager.Metadata(clientID)
if md == nil || err != nil {
log.Errorf("Failed to find clientID: %s, error=%v", clientID, err)
respondError()
return
}
log.Infof("Authenticated token for client ID %s", clientID)
c.next.ServeHTTP(w, r)
}
// getClientIDFromAuthorizedRequest will extract the clientID from the bearer token.
func getClientIDFromAuthorizedRequest(r *http.Request) (string, error) {
rawToken, err := oidc.ExtractBearerToken(r)
if err != nil {
return "", err
}
jwt, err := jose.ParseJWT(rawToken)
if err != nil {
return "", err
}
claims, err := jwt.Claims()
if err != nil {
return "", err
}
sub, ok, err := claims.StringClaim("sub")
if err != nil {
return "", fmt.Errorf("failed to parse 'sub' claim: %v", err)
}
if !ok || sub == "" {
return "", errors.New("missing required 'sub' claim")
}
return sub, nil
}