authentication; enable only (for now) (#11)

This commit is contained in:
Michael Quigley 2022-07-27 14:45:16 -04:00
parent 4311d89526
commit 6156005446
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
19 changed files with 170 additions and 181 deletions

View File

@ -15,7 +15,7 @@ zrokDir=$(realpath "$scriptDir/..")
zrokSpec=$(realpath "$zrokDir/specs/zrok.yml")
echo "...generating zrok server"
swagger generate server -f "$zrokSpec" -s rest_server_zrok -t "$zrokDir" -m "rest_model_zrok" --exclude-main
swagger generate server -P rest_model_zrok.Principal -f "$zrokSpec" -s rest_server_zrok -t "$zrokDir" -m "rest_model_zrok" --exclude-main
echo "...generating zrok client"
swagger generate client -f "$zrokSpec" -c rest_client_zrok -t "$zrokDir" -m "rest_model_zrok"
swagger generate client -P rest_model_zrok.Principal -f "$zrokSpec" -c rest_client_zrok -t "$zrokDir" -m "rest_model_zrok"

View File

@ -25,6 +25,6 @@ var apiVersionCmd = &cobra.Command{
if err != nil {
panic(err)
}
logrus.Infof("found api version [%v]", resp.Payload.Version)
logrus.Infof("found api version [%v]", resp.Payload)
},
}

View File

@ -1,8 +1,8 @@
package main
import (
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/identity"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
"github.com/openziti-test-kitchen/zrok/zrokdir"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -23,11 +23,9 @@ func enable(_ *cobra.Command, args []string) {
token := args[0]
zrok := newZrokClient()
auth := httptransport.APIKeyAuth("X-TOKEN", "header", token)
req := identity.NewEnableParams()
req.Body = &rest_model_zrok.EnableRequest{
Token: token,
}
resp, err := zrok.Identity.Enable(req)
resp, err := zrok.Identity.Enable(req, auth)
if err != nil {
panic(err)
}

View File

@ -27,12 +27,12 @@ func createAccountHandler(params identity.CreateAccountParams) middleware.Respon
Password: hashPassword(params.Body.Password),
Token: token,
}
tx, err := str.Begin()
tx, err := Str.Begin()
if err != nil {
logrus.Errorf("error starting transaction: %v", err)
return identity.NewCreateAccountInternalServerError().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))
}
id, err := str.CreateAccount(a, tx)
id, err := Str.CreateAccount(a, tx)
if err != nil {
logrus.Errorf("error creating account: %v", err)
_ = tx.Rollback()

View File

@ -4,7 +4,6 @@ import (
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime/middleware"
"github.com/openziti-test-kitchen/zrok/controller/store"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok/operations"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok/operations/identity"
@ -13,7 +12,7 @@ import (
"github.com/pkg/errors"
)
var str *store.Store
var Str *store.Store
func Run(cfg *Config) error {
swaggerSpec, err := loads.Embedded(rest_server_zrok.SwaggerJSON, rest_server_zrok.FlatSwaggerJSON)
@ -22,6 +21,7 @@ func Run(cfg *Config) error {
}
api := operations.NewZrokAPI(swaggerSpec)
api.KeyAuth = ZrokAuthenticate
api.MetadataVersionHandler = metadata.VersionHandlerFunc(versionHandler)
api.IdentityCreateAccountHandler = identity.CreateAccountHandlerFunc(createAccountHandler)
api.IdentityEnableHandler = identity.EnableHandlerFunc(enableHandler)
@ -29,7 +29,7 @@ func Run(cfg *Config) error {
api.TunnelUntunnelHandler = tunnel.UntunnelHandlerFunc(untunnelHandler)
if v, err := store.Open(cfg.Store); err == nil {
str = v
Str = v
} else {
return errors.Wrap(err, "error opening store")
}
@ -46,5 +46,5 @@ func Run(cfg *Config) error {
}
func versionHandler(_ metadata.VersionParams) middleware.Responder {
return metadata.NewVersionOK().WithPayload(&rest_model_zrok.Version{Version: "v0.0.1; sk3tc4"})
return metadata.NewVersionOK().WithPayload("v0.0.2")
}

View File

@ -18,13 +18,13 @@ import (
"time"
)
func enableHandler(params identity.EnableParams) middleware.Responder {
tx, err := str.Begin()
func enableHandler(_ identity.EnableParams, principal *rest_model_zrok.Principal) middleware.Responder {
tx, err := Str.Begin()
if err != nil {
logrus.Errorf("error starting transaction: %v", err)
return identity.NewCreateAccountInternalServerError().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))
}
a, err := str.FindAccountWithToken(params.Body.Token, tx)
a, err := Str.FindAccountWithToken(string(*principal), tx)
if err != nil {
logrus.Errorf("error finding account: %v", err)
return identity.NewCreateAccountBadRequest().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))

View File

@ -4,11 +4,27 @@ import (
"crypto/rand"
"crypto/x509"
"encoding/hex"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
"github.com/openziti/edge/rest_management_api_client"
"github.com/openziti/edge/rest_util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func ZrokAuthenticate(token string) (*rest_model_zrok.Principal, error) {
logrus.Infof("authenticating")
tx, err := Str.Begin()
if err != nil {
return nil, err
}
if a, err := Str.FindAccountWithToken(token, tx); err == nil {
principal := rest_model_zrok.Principal(a.Token)
return &principal, nil
} else {
return nil, errors.Wrap(err, "error authenticating")
}
}
func edgeClient() (*rest_management_api_client.ZitiEdgeManagement, error) {
ctrlAddress := "https://linux:1280"
caCerts, err := rest_util.GetControllerWellKnownCas(ctrlAddress)

View File

@ -14,8 +14,6 @@ import (
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
)
// NewEnableParams creates a new EnableParams object,
@ -60,10 +58,6 @@ func NewEnableParamsWithHTTPClient(client *http.Client) *EnableParams {
Typically these are written to a http.Request.
*/
type EnableParams struct {
// Body.
Body *rest_model_zrok.EnableRequest
timeout time.Duration
Context context.Context
HTTPClient *http.Client
@ -117,17 +111,6 @@ func (o *EnableParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the enable params
func (o *EnableParams) WithBody(body *rest_model_zrok.EnableRequest) *EnableParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the enable params
func (o *EnableParams) SetBody(body *rest_model_zrok.EnableRequest) {
o.Body = body
}
// WriteToRequest writes these params to a swagger request
func (o *EnableParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
@ -135,11 +118,6 @@ func (o *EnableParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Regist
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)

View File

@ -32,7 +32,7 @@ type ClientOption func(*runtime.ClientOperation)
type ClientService interface {
CreateAccount(params *CreateAccountParams, opts ...ClientOption) (*CreateAccountCreated, error)
Enable(params *EnableParams, opts ...ClientOption) (*EnableCreated, error)
Enable(params *EnableParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*EnableCreated, error)
SetTransport(transport runtime.ClientTransport)
}
@ -78,7 +78,7 @@ func (a *Client) CreateAccount(params *CreateAccountParams, opts ...ClientOption
/*
Enable enable API
*/
func (a *Client) Enable(params *EnableParams, opts ...ClientOption) (*EnableCreated, error) {
func (a *Client) Enable(params *EnableParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*EnableCreated, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewEnableParams()
@ -92,6 +92,7 @@ func (a *Client) Enable(params *EnableParams, opts ...ClientOption) (*EnableCrea
Schemes: []string{"http"},
Params: params,
Reader: &EnableReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}

View File

@ -44,22 +44,20 @@ func NewVersionOK() *VersionOK {
retrieve the current server version
*/
type VersionOK struct {
Payload *rest_model_zrok.Version
Payload rest_model_zrok.Version
}
func (o *VersionOK) Error() string {
return fmt.Sprintf("[GET /version][%d] versionOK %+v", 200, o.Payload)
}
func (o *VersionOK) GetPayload() *rest_model_zrok.Version {
func (o *VersionOK) GetPayload() rest_model_zrok.Version {
return o.Payload
}
func (o *VersionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(rest_model_zrok.Version)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}

View File

@ -0,0 +1,27 @@
// Code generated by go-swagger; DO NOT EDIT.
package rest_model_zrok
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
)
// Principal principal
//
// swagger:model principal
type Principal string
// Validate validates this principal
func (m Principal) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this principal based on context it is used
func (m Principal) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}

View File

@ -9,42 +9,19 @@ import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// Version version
//
// swagger:model version
type Version struct {
// version
Version string `json:"version,omitempty"`
}
type Version string
// Validate validates this version
func (m *Version) Validate(formats strfmt.Registry) error {
func (m Version) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this version based on context it is used
func (m *Version) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *Version) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *Version) UnmarshalBinary(b []byte) error {
var res Version
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
func (m Version) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}

View File

@ -24,7 +24,6 @@ func configureAPI(api *operations.ZrokAPI) http.Handler {
api.UseSwaggerUI()
api.JSONConsumer = runtime.JSONConsumer()
api.JSONProducer = runtime.JSONProducer()
api.PreServerShutdown = func() {}
api.ServerShutdown = func() {}

View File

@ -73,19 +73,15 @@ func init() {
},
"/enable": {
"post": {
"security": [
{
"key": []
}
],
"tags": [
"identity"
],
"operationId": "enable",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/enableRequest"
}
}
],
"responses": {
"201": {
"description": "environment enabled",
@ -201,14 +197,6 @@ func init() {
}
}
},
"enableRequest": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"enableResponse": {
"type": "object",
"properties": {
@ -223,6 +211,9 @@ func init() {
"errorMessage": {
"type": "string"
},
"principal": {
"type": "string"
},
"tunnelRequest": {
"type": "object",
"properties": {
@ -251,12 +242,14 @@ func init() {
}
},
"version": {
"type": "object",
"properties": {
"version": {
"type": "string"
}
}
"type": "string"
}
},
"securityDefinitions": {
"key": {
"type": "apiKey",
"name": "x-token",
"in": "header"
}
}
}`))
@ -316,19 +309,15 @@ func init() {
},
"/enable": {
"post": {
"security": [
{
"key": []
}
],
"tags": [
"identity"
],
"operationId": "enable",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/enableRequest"
}
}
],
"responses": {
"201": {
"description": "environment enabled",
@ -444,14 +433,6 @@ func init() {
}
}
},
"enableRequest": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"enableResponse": {
"type": "object",
"properties": {
@ -466,6 +447,9 @@ func init() {
"errorMessage": {
"type": "string"
},
"principal": {
"type": "string"
},
"tunnelRequest": {
"type": "object",
"properties": {
@ -494,12 +478,14 @@ func init() {
}
},
"version": {
"type": "object",
"properties": {
"version": {
"type": "string"
}
}
"type": "string"
}
},
"securityDefinitions": {
"key": {
"type": "apiKey",
"name": "x-token",
"in": "header"
}
}
}`))

View File

@ -9,19 +9,21 @@ import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
)
// EnableHandlerFunc turns a function with the right signature into a enable handler
type EnableHandlerFunc func(EnableParams) middleware.Responder
type EnableHandlerFunc func(EnableParams, *rest_model_zrok.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn EnableHandlerFunc) Handle(params EnableParams) middleware.Responder {
return fn(params)
func (fn EnableHandlerFunc) Handle(params EnableParams, principal *rest_model_zrok.Principal) middleware.Responder {
return fn(params, principal)
}
// EnableHandler interface for that can handle valid enable params
type EnableHandler interface {
Handle(EnableParams) middleware.Responder
Handle(EnableParams, *rest_model_zrok.Principal) middleware.Responder
}
// NewEnable creates a new http.Handler for the enable operation
@ -45,12 +47,25 @@ func (o *Enable) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
*r = *rCtx
}
var Params = NewEnableParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *rest_model_zrok.Principal
if uprinc != nil {
principal = uprinc.(*rest_model_zrok.Principal) // this is really a rest_model_zrok.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@ -6,15 +6,10 @@ package identity
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/validate"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
)
// NewEnableParams creates a new EnableParams object
@ -33,11 +28,6 @@ type EnableParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
In: body
*/
Body *rest_model_zrok.EnableRequest
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
@ -49,27 +39,6 @@ func (o *EnableParams) BindRequest(r *http.Request, route *middleware.MatchedRou
o.HTTPRequest = r
if runtime.HasBody(r) {
defer r.Body.Close()
var body rest_model_zrok.EnableRequest
if err := route.Consumer.Consume(r.Body, &body); err != nil {
res = append(res, errors.NewParseError("body", "body", "", err))
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
ctx := validate.WithOperationRequest(context.Background())
if err := body.ContextValidate(ctx, route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}

View File

@ -25,7 +25,7 @@ type VersionOK struct {
/*
In: Body
*/
Payload *rest_model_zrok.Version `json:"body,omitempty"`
Payload rest_model_zrok.Version `json:"body,omitempty"`
}
// NewVersionOK creates VersionOK with default headers values
@ -35,13 +35,13 @@ func NewVersionOK() *VersionOK {
}
// WithPayload adds the payload to the version o k response
func (o *VersionOK) WithPayload(payload *rest_model_zrok.Version) *VersionOK {
func (o *VersionOK) WithPayload(payload rest_model_zrok.Version) *VersionOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the version o k response
func (o *VersionOK) SetPayload(payload *rest_model_zrok.Version) {
func (o *VersionOK) SetPayload(payload rest_model_zrok.Version) {
o.Payload = payload
}
@ -49,10 +49,8 @@ func (o *VersionOK) SetPayload(payload *rest_model_zrok.Version) {
func (o *VersionOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}

View File

@ -19,6 +19,7 @@ import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok/operations/identity"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok/operations/metadata"
"github.com/openziti-test-kitchen/zrok/rest_server_zrok/operations/tunnel"
@ -49,7 +50,7 @@ func NewZrokAPI(spec *loads.Document) *ZrokAPI {
IdentityCreateAccountHandler: identity.CreateAccountHandlerFunc(func(params identity.CreateAccountParams) middleware.Responder {
return middleware.NotImplemented("operation identity.CreateAccount has not yet been implemented")
}),
IdentityEnableHandler: identity.EnableHandlerFunc(func(params identity.EnableParams) middleware.Responder {
IdentityEnableHandler: identity.EnableHandlerFunc(func(params identity.EnableParams, principal *rest_model_zrok.Principal) middleware.Responder {
return middleware.NotImplemented("operation identity.Enable has not yet been implemented")
}),
TunnelTunnelHandler: tunnel.TunnelHandlerFunc(func(params tunnel.TunnelParams) middleware.Responder {
@ -61,6 +62,13 @@ func NewZrokAPI(spec *loads.Document) *ZrokAPI {
MetadataVersionHandler: metadata.VersionHandlerFunc(func(params metadata.VersionParams) middleware.Responder {
return middleware.NotImplemented("operation metadata.Version has not yet been implemented")
}),
// Applies when the "x-token" header is set
KeyAuth: func(token string) (*rest_model_zrok.Principal, error) {
return nil, errors.NotImplemented("api key auth (key) x-token from header param [x-token] has not yet been implemented")
},
// default authorizer is authorized meaning no requests are blocked
APIAuthorizer: security.Authorized(),
}
}
@ -97,6 +105,13 @@ type ZrokAPI struct {
// - application/zrok.v1+json
JSONProducer runtime.Producer
// KeyAuth registers a function that takes a token and returns a principal
// it performs authentication based on an api key x-token provided in the header
KeyAuth func(string) (*rest_model_zrok.Principal, error)
// APIAuthorizer provides access control (ACL/RBAC/ABAC) by providing access to the request and authenticated principal
APIAuthorizer runtime.Authorizer
// IdentityCreateAccountHandler sets the operation handler for the create account operation
IdentityCreateAccountHandler identity.CreateAccountHandler
// IdentityEnableHandler sets the operation handler for the enable operation
@ -184,6 +199,10 @@ func (o *ZrokAPI) Validate() error {
unregistered = append(unregistered, "JSONProducer")
}
if o.KeyAuth == nil {
unregistered = append(unregistered, "XTokenAuth")
}
if o.IdentityCreateAccountHandler == nil {
unregistered = append(unregistered, "identity.CreateAccountHandler")
}
@ -214,12 +233,23 @@ func (o *ZrokAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *h
// AuthenticatorsFor gets the authenticators for the specified security schemes
func (o *ZrokAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
return nil
result := make(map[string]runtime.Authenticator)
for name := range schemes {
switch name {
case "key":
scheme := schemes[name]
result[name] = o.APIKeyAuthenticator(scheme.Name, scheme.In, func(token string) (interface{}, error) {
return o.KeyAuth(token)
})
}
}
return result
}
// Authorizer returns the registered authorizer
func (o *ZrokAPI) Authorizer() runtime.Authorizer {
return nil
return o.APIAuthorizer
}
// ConsumersFor gets the consumers for the specified media types.

View File

@ -3,6 +3,12 @@ info:
title: zrok
version: 1.0.0
securityDefinitions:
key:
type: apiKey
in: header
name: x-token
paths:
/account:
post:
@ -31,12 +37,9 @@ paths:
post:
tags:
- identity
security:
- key: []
operationId: enable
parameters:
- name: body
in: body
schema:
$ref: "#/definitions/enableRequest"
responses:
201:
description: environment enabled
@ -96,11 +99,6 @@ paths:
$ref: "#/definitions/version"
definitions:
version:
type: object
properties:
version:
type: string
accountRequest:
type: object
properties:
@ -113,11 +111,6 @@ definitions:
properties:
token:
type: string
enableRequest:
type: object
properties:
token:
type: string
enableResponse:
type: object
properties:
@ -127,6 +120,8 @@ definitions:
type: string
errorMessage:
type: string
principal:
type: string
tunnelRequest:
type: object
properties:
@ -144,6 +139,8 @@ definitions:
properties:
service:
type: string
version:
type: string
produces:
- application/zrok.v1+json