// 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) } else if !ok || sub == "" { return "", errors.New("missing required 'sub' claim") } return sub, nil }
func (l *TokenValidator) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { log.Info("validating") rawToken, err := oidc.ExtractBearerToken(r) if err != nil { log.Error("token.go: failed to get jwt from header") writeError(rw, http.StatusUnauthorized, "missing or invalid token") return } jwt, err := jose.ParseJWT(rawToken) if err != nil { log.Error("token.go: failed to parse jwt") writeError(rw, http.StatusUnauthorized, "missing or invalid token") return } err = l.accounts.Oidc.VerifyJWT(jwt) if err != nil { log.Errorf("token.go: Failed to verify signature: %v", err) writeError(rw, http.StatusUnauthorized, "invalid token") } claims, err := jwt.Claims() if err != nil { log.Error("token.go: failed to get claims", err) writeError(rw, http.StatusUnauthorized, "missing or invalid token") return } sub, ok, err := claims.StringClaim("sub") if err != nil { log.Errorf("token.go: failed to parse 'sub' claim: %v", err) writeError(rw, http.StatusUnauthorized, "missing or invalid token") return } if !ok || sub == "" { log.Error("token.go: missing required 'sub' claim") writeError(rw, http.StatusUnauthorized, "missing or invalid token") return } fmt.Println("token.go: verified token for", sub) r.Header.Set("sub", sub) next(rw, r) }
func (s *UserMgmtServer) getCreds(r *http.Request) (api.Creds, error) { token, err := oidc.ExtractBearerToken(r) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } jwt, err := jose.ParseJWT(token) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } claims, err := jwt.Claims() if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } clientID, ok, err := claims.StringClaim("aud") if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } if !ok || clientID == "" { return api.Creds{}, errors.New("no aud(client ID) claim") } verifier := s.jwtvFactory(clientID) if err := verifier.Verify(jwt); err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } sub, ok, err := claims.StringClaim("sub") if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } if !ok || sub == "" { return api.Creds{}, api.ErrorUnauthorized } usr, err := s.um.Get(sub) if err != nil { if err == user.ErrorNotFound { return api.Creds{}, api.ErrorUnauthorized } log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } isAdmin, err := s.cir.IsDexAdmin(clientID) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } if !isAdmin { return api.Creds{}, api.ErrorForbidden } return api.Creds{ ClientID: clientID, User: usr, }, nil }
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.ciRepo == nil { log.Errorf("Misconfigured clientTokenMiddleware, ClientIdentityRepo 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 } else 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 } else 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.ciRepo.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) }
func (s *UserMgmtServer) getCreds(r *http.Request, requiresAdmin bool) (api.Creds, error) { token, err := oidc.ExtractBearerToken(r) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } jwt, err := jose.ParseJWT(token) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } claims, err := jwt.Claims() if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, api.ErrorUnauthorized } // The "aud" claim is allowed to be both a list of clients or a single client. Check for both cases. clientIDs, ok, err := claims.StringsClaim("aud") if err != nil || !ok { clientID, ok, err := claims.StringClaim("aud") if err != nil { log.Errorf("userMgmtServer: GetCreds failed to parse 'aud' claim: %q", err) return api.Creds{}, api.ErrorUnauthorized } if !ok || clientID == "" { return api.Creds{}, api.ErrorUnauthorized } clientIDs = []string{clientID} } if len(clientIDs) == 0 { log.Errorf("userMgmtServer: GetCreds err: no client in audience") return api.Creds{}, api.ErrorUnauthorized } // Verify that the JWT is signed by this server, has the correct issuer, hasn't expired, etc. // While we don't actualy care which client the token was issued for (we'll check that later), // go-oidc doesn't provide any methods which don't require passing a client ID. // // TODO(ericchiang): Add a verifier to go-oidc that doesn't require a client ID. verifier := s.jwtvFactory(clientIDs[0]) if err := verifier.Verify(jwt); err != nil { log.Errorf("userMgmtServer: GetCreds err: failed to verify token %q", err) return api.Creds{}, api.ErrorUnauthorized } sub, ok, err := claims.StringClaim("sub") if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } if !ok || sub == "" { return api.Creds{}, api.ErrorUnauthorized } if s.allowClientCredsAuth && (len(clientIDs) == 1) && (sub == clientIDs[0]) { isAdmin, err := s.cm.IsDexAdmin(clientIDs[0]) if err != nil { log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } if requiresAdmin && !isAdmin { return api.Creds{}, api.ErrorForbidden } return api.Creds{ ClientIDs: clientIDs, }, nil } usr, err := s.um.Get(sub) if err != nil { if err == user.ErrorNotFound { return api.Creds{}, api.ErrorUnauthorized } log.Errorf("userMgmtServer: GetCreds err: %q", err) return api.Creds{}, err } i := 0 for _, clientID := range clientIDs { // Make sure the client actually exists. isAdmin, err := s.cm.IsDexAdmin(clientID) if err != nil { log.Errorf("userMgmtServer: GetCreds err: failed to get client %v", err) return api.Creds{}, err } // If the endpoint requires an admin client, filter out clients which are not admins. if requiresAdmin && !isAdmin { continue } clientIDs[i] = clientID i++ } clientIDs = clientIDs[:i] if len(clientIDs) == 0 { return api.Creds{}, api.ErrorForbidden } return api.Creds{ ClientIDs: clientIDs, User: usr, }, nil }