Merge branch 'service-accounts' of github.com:caos/oidc into service-accounts

This commit is contained in:
adlerhurst 2020-09-16 14:12:45 +02:00
commit ad0966c1ab
6 changed files with 128 additions and 219 deletions

35
pkg/rp/cli/cli.go Normal file
View file

@ -0,0 +1,35 @@
package cli
import (
"context"
"net/http"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/rp"
"github.com/caos/oidc/pkg/utils"
)
const (
loginPath = "/login"
)
func CodeFlow(relayingParty rp.RelayingParty, callbackPath, port string, stateProvider func() string) *oidc.Tokens {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var token *oidc.Tokens
callback := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string) {
token = tokens
msg := "<p><strong>Success!</strong></p>"
msg = msg + "<p>You are authenticated and can now return to the CLI.</p>"
w.Write([]byte(msg))
}
http.Handle(loginPath, rp.AuthURLHandler(stateProvider, relayingParty))
http.Handle(callbackPath, rp.CodeExchangeHandler(callback, relayingParty))
utils.StartServer(ctx, port)
utils.OpenBrowser("http://localhost:" + port + loginPath)
return token
}

View file

@ -40,30 +40,31 @@ type RelayingParty interface {
ErrorHandler() func(http.ResponseWriter, *http.Request, string, string, string)
}
type ErrorHandler func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string)
var (
DefaultErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
DefaultErrorHandler ErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
}
)
type relayingParty struct {
endpoints Endpoints
config *Configuration
pkce bool
issuer string
endpoints Endpoints
oauthConfig *oauth2.Config
oauth2Only bool
pkce bool
httpClient *http.Client
cookieHandler *utils.CookieHandler
errorHandler func(http.ResponseWriter, *http.Request, string, string, string)
errorHandler func(http.ResponseWriter, *http.Request, string, string, string)
idTokenVerifier IDTokenVerifier
verifierOpts []VerifierOption
oauth2Only bool
}
func (rp *relayingParty) OAuthConfig() *oauth2.Config {
return rp.config.Config
return rp.oauthConfig
}
func (rp *relayingParty) IsPKCE() bool {
@ -84,97 +85,69 @@ func (rp *relayingParty) IsOAuth2Only() bool {
func (rp *relayingParty) IDTokenVerifier() IDTokenVerifier {
if rp.idTokenVerifier == nil {
rp.idTokenVerifier = NewIDTokenVerifier(rp.config.Issuer, rp.config.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL), rp.verifierOpts...)
rp.idTokenVerifier = NewIDTokenVerifier(rp.issuer, rp.oauthConfig.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL), rp.verifierOpts...)
}
return rp.idTokenVerifier
}
func (rp *relayingParty) Client(ctx context.Context, token *oauth2.Token) *http.Client {
return rp.config.Config.Client(ctx, token)
return rp.oauthConfig.Client(ctx, token)
}
func (rp *relayingParty) ErrorHandler() func(http.ResponseWriter, *http.Request, string, string, string) {
if rp.errorHandler == nil {
rp.errorHandler = DefaultErrorHandler
}
return rp.errorHandler
}
//NewRelayingParty creates a DelegationTokenExchangeRP with the given
//Config and possible configOptions
//it will run discovery on the provided issuer if AuthURL and TokenURL are not set
//if no verifier is provided using the options the `DefaultVerifier` is set
func NewRelayingParty(config *Configuration, options ...Option) (RelayingParty, error) {
isOpenID := isOpenID(config.Scopes)
//NewRelayingPartyOAuth creates an (OAuth2) RelayingParty with the given
//OAuth2 Config and possible configOptions
//it will use the AuthURL and TokenURL set in config
func NewRelayingPartyOAuth(config *oauth2.Config, options ...Option) (RelayingParty, error) {
rp := &relayingParty{
config: config,
httpClient: utils.DefaultHTTPClient,
oauth2Only: !isOpenID,
oauthConfig: config,
httpClient: utils.DefaultHTTPClient,
oauth2Only: true,
}
for _, optFunc := range options {
optFunc(rp)
}
if isOpenID && config.Endpoint.AuthURL == "" && config.Endpoint.TokenURL == "" {
endpoints, err := Discover(config.Issuer, rp.httpClient)
if err != nil {
return nil, err
}
rp.config.Endpoint = endpoints.Endpoint
rp.endpoints = endpoints
}
if rp.errorHandler == nil {
rp.errorHandler = DefaultErrorHandler
}
if isOpenID && rp.idTokenVerifier == nil {
rp.idTokenVerifier = NewIDTokenVerifier(config.Issuer, config.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL))
}
return rp, nil
}
func NewRelayingParty2(clientID, clientSecret, redirectURI string, options ...Option) (RelayingParty, error) {
//NewRelayingPartyOIDC creates an (OIDC) RelayingParty with the given
//issuer, clientID, clientSecret, redirectURI, scopes and possible configOptions
//it will run discovery on the provided issuer and use the found endpoints
func NewRelayingPartyOIDC(issuer, clientID, clientSecret, redirectURI string, scopes []string, options ...Option) (RelayingParty, error) {
rp := &relayingParty{
config: &Configuration{
Config: &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURL: redirectURI,
},
issuer: issuer,
oauthConfig: &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURL: redirectURI,
Scopes: scopes,
},
httpClient: utils.DefaultHTTPClient,
oauth2Only: true,
oauth2Only: false,
}
for _, optFunc := range options {
optFunc(rp)
}
if !rp.oauth2Only && rp.config.Endpoint.AuthURL == "" && rp.config.Endpoint.TokenURL == "" {
endpoints, err := Discover(rp.config.Issuer, rp.httpClient)
if err != nil {
return nil, err
}
rp.config.Endpoint = endpoints.Endpoint
rp.endpoints = endpoints
}
if rp.errorHandler == nil {
rp.errorHandler = DefaultErrorHandler
endpoints, err := Discover(rp.issuer, rp.httpClient)
if err != nil {
return nil, err
}
rp.oauthConfig.Endpoint = endpoints.Endpoint
rp.endpoints = endpoints
return rp, nil
}
func WithOIDC(issuer string, scopes []string) Option {
return func(rp *relayingParty) {
rp.config.Issuer = issuer
rp.config.Scopes = scopes
rp.oauth2Only = false
}
}
//DefaultRPOpts is the type for providing dynamic options to the DefaultRP
type Option func(*relayingParty)
@ -202,6 +175,12 @@ func WithHTTPClient(client *http.Client) Option {
}
}
func WithErrorHandler(errorHandler ErrorHandler) Option {
return func(rp *relayingParty) {
rp.errorHandler = errorHandler
}
}
func WithVerifierOpts(opts ...VerifierOption) Option {
return func(rp *relayingParty) {
rp.verifierOpts = opts
@ -433,12 +412,3 @@ func WithCodeVerifier(codeVerifier string) CodeExchangeOpt {
return []oauth2.AuthCodeOption{oauth2.SetAuthURLParam("code_verifier", codeVerifier)}
}
}
func isOpenID(scopes []string) bool {
for _, scope := range scopes {
if scope == oidc.ScopeOpenID {
return true
}
}
return false
}