Http: add pluggable authentication and token (#20066)
This commit is contained in:
parent
6f5c0b6478
commit
986772d525
6 changed files with 140 additions and 48 deletions
7
plugin/auth/api.go
Normal file
7
plugin/auth/api.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package auth
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Authorizer interface {
|
||||
Transport(base http.RoundTripper) (http.RoundTripper, error)
|
||||
}
|
||||
26
plugin/auth/config.go
Normal file
26
plugin/auth/config.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
reg "github.com/evcc-io/evcc/util/registry"
|
||||
)
|
||||
|
||||
var registry = reg.New[Authorizer]("auth")
|
||||
|
||||
// NewFromConfig creates auth from configuration
|
||||
func NewFromConfig(ctx context.Context, typ string, other map[string]any) (Authorizer, error) {
|
||||
factory, err := registry.Get(strings.ToLower(typ))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := factory(ctx, other)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("cannot create auth type '%s': %w", typ, err)
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
27
plugin/auth/nop.go
Normal file
27
plugin/auth/nop.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
type nop struct{}
|
||||
|
||||
func init() {
|
||||
registry.AddCtx("nop", NewNopFromConfig)
|
||||
}
|
||||
|
||||
func NewNopFromConfig(ctx context.Context, other map[string]any) (Authorizer, error) {
|
||||
var cc struct{}
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(nop), nil
|
||||
}
|
||||
|
||||
func (p *nop) Transport(base http.RoundTripper) (http.RoundTripper, error) {
|
||||
return base, nil
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/transport"
|
||||
"github.com/gregjones/httpcache"
|
||||
"github.com/jpfielding/go-http-digest/pkg/digest"
|
||||
)
|
||||
|
||||
// HTTP implements HTTP request provider
|
||||
|
|
@ -33,11 +32,6 @@ func init() {
|
|||
|
||||
var mc = httpcache.NewMemoryCache()
|
||||
|
||||
// Auth is the authorization config
|
||||
type Auth struct {
|
||||
Type, User, Password string
|
||||
}
|
||||
|
||||
// NewHTTPPluginFromConfig creates a HTTP provider
|
||||
func NewHTTPPluginFromConfig(ctx context.Context, other map[string]interface{}) (Plugin, error) {
|
||||
cc := struct {
|
||||
|
|
@ -80,18 +74,21 @@ func NewHTTPPluginFromConfig(ctx context.Context, other map[string]interface{})
|
|||
|
||||
p.getter = defaultGetters(p, cc.Scale)
|
||||
|
||||
var err error
|
||||
if cc.Auth.Type != "" {
|
||||
_, err = p.WithAuth(cc.Auth.Type, cc.Auth.User, cc.Auth.Password)
|
||||
if cc.Auth.Type != "" || cc.Auth.Source != "" {
|
||||
transport, err := cc.Auth.Transport(ctx, p.Client.Transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Client.Transport = transport
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
var pipe *pipeline.Pipeline
|
||||
pipe, err = pipeline.New(log, cc.Settings)
|
||||
p = p.WithPipeline(pipe)
|
||||
pipe, err := pipeline.New(log, cc.Settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.pipeline = pipe
|
||||
|
||||
return p, err
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// NewHTTP create HTTP provider
|
||||
|
|
@ -128,7 +125,12 @@ func NewHTTP(log *util.Logger, method, uri string, insecure bool, cache time.Dur
|
|||
|
||||
// WithBody adds request body
|
||||
func (p *HTTP) WithBody(body string) *HTTP {
|
||||
p.body = body
|
||||
if body != "" {
|
||||
p.body = body
|
||||
if p.method == http.MethodGet {
|
||||
p.method = http.MethodPost
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
@ -138,28 +140,6 @@ func (p *HTTP) WithHeaders(headers map[string]string) *HTTP {
|
|||
return p
|
||||
}
|
||||
|
||||
// WithPipeline adds a processing pipeline
|
||||
func (p *HTTP) WithPipeline(pipeline *pipeline.Pipeline) *HTTP {
|
||||
p.pipeline = pipeline
|
||||
return p
|
||||
}
|
||||
|
||||
// WithAuth adds authorized transport
|
||||
func (p *HTTP) WithAuth(typ, user, password string) (*HTTP, error) {
|
||||
switch strings.ToLower(typ) {
|
||||
case "basic":
|
||||
p.Client.Transport = transport.BasicAuth(user, password, p.Client.Transport)
|
||||
case "bearer":
|
||||
p.Client.Transport = transport.BearerAuth(password, p.Client.Transport)
|
||||
case "digest":
|
||||
p.Client.Transport = digest.NewTransport(user, password, p.Client.Transport)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown auth type '%s'", typ)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// request executes the configured request or returns the cached value
|
||||
func (p *HTTP) request(url string, body string) ([]byte, error) {
|
||||
var b io.Reader
|
||||
|
|
|
|||
52
plugin/http_auth.go
Normal file
52
plugin/http_auth.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/evcc-io/evcc/plugin/auth"
|
||||
"github.com/evcc-io/evcc/util/transport"
|
||||
"github.com/jpfielding/go-http-digest/pkg/digest"
|
||||
)
|
||||
|
||||
// Auth is the authorization config
|
||||
type Auth struct {
|
||||
Type, User, Password, Token string
|
||||
|
||||
Source string
|
||||
Other map[string]any `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
func (p *Auth) Transport(ctx context.Context, base http.RoundTripper) (http.RoundTripper, error) {
|
||||
switch strings.ToLower(p.Type) {
|
||||
case "digest":
|
||||
return digest.NewTransport(p.User, p.Password, base), nil
|
||||
|
||||
case "basic":
|
||||
return transport.BasicAuth(p.User, p.Password, base), nil
|
||||
|
||||
case "bearer":
|
||||
return transport.BearerAuth(p.Token, base), nil
|
||||
|
||||
default:
|
||||
if p.Source == "" {
|
||||
return nil, fmt.Errorf("unknown auth type '%s'", p.Type)
|
||||
}
|
||||
|
||||
if p.User != "" {
|
||||
p.Other["user"] = p.User
|
||||
}
|
||||
if p.Password != "" {
|
||||
p.Other["password"] = p.Password
|
||||
}
|
||||
|
||||
authorizer, err := auth.NewFromConfig(ctx, p.Source, p.Other)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authorizer.Transport(base)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -40,7 +40,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -50,7 +50,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -60,7 +60,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -73,7 +73,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -84,7 +84,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -96,7 +96,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -106,7 +106,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -116,7 +116,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -129,7 +129,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
@ -140,7 +140,7 @@ render: |
|
|||
{{- if .token }}
|
||||
auth:
|
||||
type: bearer
|
||||
password: {{ .token }}
|
||||
token: {{ .token }}
|
||||
insecure: true
|
||||
{{- end }}
|
||||
cache: {{ .cache }}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue