diff --git a/handlers/jwt.go b/handlers/jwt.go index 4a761c3b41..5fd525b393 100644 --- a/handlers/jwt.go +++ b/handlers/jwt.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "strings" + "log" jwt "github.com/dgrijalva/jwt-go" ) @@ -32,6 +33,7 @@ func AuthorizedToken(opts JWTOpts, next http.Handler) http.Handler { opts.EnsureDefaults() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Check for the HTTP Authorization header. + log.Print("do a thing!") if s := r.Header.Get("Authorization"); s != "" { // Check for Bearer token. strs := strings.Split(s, " ") @@ -76,9 +78,3 @@ func AuthorizedToken(opts JWTOpts, next http.Handler) http.Handler { w.WriteHeader(http.StatusUnauthorized) }) } - -// Token returns a JWT token -func NewToken(opts JWTOpts) http.Handler { - // grab https://github.com/influxdata/kapacitor/blob/04f1ab3116b6bab27cbf63cb0e6b918fc77c7320/server/server_test.go#L97 - return nil -} diff --git a/mock/handlers.go b/mock/handlers.go index 449fcd661c..e09098ab27 100644 --- a/mock/handlers.go +++ b/mock/handlers.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + jwt "github.com/dgrijalva/jwt-go" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" "github.com/influxdata/chronograf" @@ -363,3 +364,26 @@ func (m *Handler) GetMappings(ctx context.Context, params op.GetMappingsParams) } return op.NewGetMappingsOK().WithPayload(mp) } + +func (m *Handler) Token(ctx context.Context, params op.GetTokenParams) middleware.Responder { + + token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ + "sub": "bob", + "exp": time.Now().Add(time.Hour * 24 * 30).Unix(), + "username": "bob", + "email": "bob@mail.com", + "nbf": time.Now().Unix(), + "iat": time.Now().Unix(), + }) + + // sign token with secret + ts, err := token.SignedString([]byte("secret")) + if err != nil { + errMsg := &models.Error{Code: 500, Message: "Failed to sign token"} + return op.NewGetTokenDefault(500).WithPayload(errMsg) + } + + t := models.Token(ts) + + return op.NewGetTokenOK().WithPayload(t) +} diff --git a/models/token.go b/models/token.go new file mode 100644 index 0000000000..c7903ac28b --- /dev/null +++ b/models/token.go @@ -0,0 +1,8 @@ +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Token a stringified JWT token. +// swagger:model Token +type Token interface{} diff --git a/restapi/configure_chronograf.go b/restapi/configure_chronograf.go index 6c08d24731..3987b92af9 100644 --- a/restapi/configure_chronograf.go +++ b/restapi/configure_chronograf.go @@ -118,6 +118,7 @@ func configureAPI(api *op.ChronografAPI) http.Handler { LayoutStore: allLayouts, } + api.GetTokenHandler = op.GetTokenHandlerFunc(mockHandler.Token) api.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.DeleteExploration) api.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.GetSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.Exploration) api.GetSourcesIDUsersUserIDExplorationsHandler = op.GetSourcesIDUsersUserIDExplorationsHandlerFunc(h.Explorations) diff --git a/restapi/operations/chronograf_api.go b/restapi/operations/chronograf_api.go index 6cd5bd6dd6..815ae8e1bc 100644 --- a/restapi/operations/chronograf_api.go +++ b/restapi/operations/chronograf_api.go @@ -91,6 +91,8 @@ type ChronografAPI struct { GetSourcesIDUsersUserIDExplorationsHandler GetSourcesIDUsersUserIDExplorationsHandler // GetSourcesIDUsersUserIDExplorationsExplorationIDHandler sets the operation handler for the get sources ID users user ID explorations exploration ID operation GetSourcesIDUsersUserIDExplorationsExplorationIDHandler GetSourcesIDUsersUserIDExplorationsExplorationIDHandler + // GetTokenHandler sets the operation handler for the get token operation + GetTokenHandler GetTokenHandler // PatchSourcesIDHandler sets the operation handler for the patch sources ID operation PatchSourcesIDHandler PatchSourcesIDHandler // PatchSourcesIDKapacitorsKapaIDHandler sets the operation handler for the patch sources ID kapacitors kapa ID operation @@ -280,6 +282,10 @@ func (o *ChronografAPI) Validate() error { unregistered = append(unregistered, "GetSourcesIDUsersUserIDExplorationsExplorationIDHandler") } + if o.GetTokenHandler == nil { + unregistered = append(unregistered, "GetTokenHandler") + } + if o.PatchSourcesIDHandler == nil { unregistered = append(unregistered, "PatchSourcesIDHandler") } @@ -540,6 +546,11 @@ func (o *ChronografAPI) initHandlerCache() { } o.handlers["GET"]["/sources/{id}/users/{user_id}/explorations/{exploration_id}"] = NewGetSourcesIDUsersUserIDExplorationsExplorationID(o.context, o.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler) + if o.handlers["GET"] == nil { + o.handlers[strings.ToUpper("GET")] = make(map[string]http.Handler) + } + o.handlers["GET"]["/token"] = NewGetToken(o.context, o.GetTokenHandler) + if o.handlers["PATCH"] == nil { o.handlers[strings.ToUpper("PATCH")] = make(map[string]http.Handler) } diff --git a/restapi/operations/get_token.go b/restapi/operations/get_token.go new file mode 100644 index 0000000000..7bda24bba1 --- /dev/null +++ b/restapi/operations/get_token.go @@ -0,0 +1,58 @@ +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + context "golang.org/x/net/context" + + middleware "github.com/go-openapi/runtime/middleware" +) + +// GetTokenHandlerFunc turns a function with the right signature into a get token handler +type GetTokenHandlerFunc func(context.Context, GetTokenParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetTokenHandlerFunc) Handle(ctx context.Context, params GetTokenParams) middleware.Responder { + return fn(ctx, params) +} + +// GetTokenHandler interface for that can handle valid get token params +type GetTokenHandler interface { + Handle(context.Context, GetTokenParams) middleware.Responder +} + +// NewGetToken creates a new http.Handler for the get token operation +func NewGetToken(ctx *middleware.Context, handler GetTokenHandler) *GetToken { + return &GetToken{Context: ctx, Handler: handler} +} + +/*GetToken swagger:route GET /token getToken + +Authentication token + +Generates a JWT authentication token + + +*/ +type GetToken struct { + Context *middleware.Context + Handler GetTokenHandler +} + +func (o *GetToken) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, _ := o.Context.RouteInfo(r) + var Params = NewGetTokenParams() + + 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(context.Background(), Params) // actually handle the request + + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/restapi/operations/get_token_parameters.go b/restapi/operations/get_token_parameters.go new file mode 100644 index 0000000000..bb7ed037bb --- /dev/null +++ b/restapi/operations/get_token_parameters.go @@ -0,0 +1,40 @@ +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" +) + +// NewGetTokenParams creates a new GetTokenParams object +// with the default values initialized. +func NewGetTokenParams() GetTokenParams { + var () + return GetTokenParams{} +} + +// GetTokenParams contains all the bound params for the get token operation +// typically these are obtained from a http.Request +// +// swagger:parameters GetToken +type GetTokenParams struct { + + // HTTP Request Object + HTTPRequest *http.Request +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls +func (o *GetTokenParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + o.HTTPRequest = r + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/restapi/operations/get_token_responses.go b/restapi/operations/get_token_responses.go new file mode 100644 index 0000000000..338ff708c1 --- /dev/null +++ b/restapi/operations/get_token_responses.go @@ -0,0 +1,103 @@ +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/influxdata/chronograf/models" +) + +/*GetTokenOK A JWT authentication token + +swagger:response getTokenOK +*/ +type GetTokenOK struct { + + // In: body + Payload models.Token `json:"body,omitempty"` +} + +// NewGetTokenOK creates GetTokenOK with default headers values +func NewGetTokenOK() *GetTokenOK { + return &GetTokenOK{} +} + +// WithPayload adds the payload to the get token o k response +func (o *GetTokenOK) WithPayload(payload models.Token) *GetTokenOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get token o k response +func (o *GetTokenOK) SetPayload(payload models.Token) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetTokenOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if err := producer.Produce(rw, o.Payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + +} + +/*GetTokenDefault Unexpected internal service error + +swagger:response getTokenDefault +*/ +type GetTokenDefault struct { + _statusCode int + + // In: body + Payload *models.Error `json:"body,omitempty"` +} + +// NewGetTokenDefault creates GetTokenDefault with default headers values +func NewGetTokenDefault(code int) *GetTokenDefault { + if code <= 0 { + code = 500 + } + + return &GetTokenDefault{ + _statusCode: code, + } +} + +// WithStatusCode adds the status to the get token default response +func (o *GetTokenDefault) WithStatusCode(code int) *GetTokenDefault { + o._statusCode = code + return o +} + +// SetStatusCode sets the status to the get token default response +func (o *GetTokenDefault) SetStatusCode(code int) { + o._statusCode = code +} + +// WithPayload adds the payload to the get token default response +func (o *GetTokenDefault) WithPayload(payload *models.Error) *GetTokenDefault { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get token default response +func (o *GetTokenDefault) SetPayload(payload *models.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetTokenDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(o._statusCode) + if o.Payload != nil { + if err := producer.Produce(rw, o.Payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/swagger.yaml b/swagger.yaml index 413c89d64a..388bf86b0e 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -1020,6 +1020,20 @@ paths: description: A processing or an unexpected error. schema: $ref: '#/definitions/Error' + /token: + get: + summary: Authentication token + description: | + Generates a JWT authentication token + responses: + 200: + description: A JWT authentication token + schema: + $ref: '#/definitions/Token' + default: + description: Unexpected internal service error + schema: + $ref: '#/definitions/Error' definitions: Kapacitors: type: object @@ -1213,6 +1227,9 @@ definitions: $ref: "#/definitions/Users" link: $ref: "#/definitions/Link" + Token: + type: object + description: a stringified JWT token. Users: type: object properties: