Example #1
0
// Create runs the create action.
func (c *UserspaceController) Create(ctx *app.CreateUserspaceContext) error {
	return models.Transactional(c.db, func(db *gorm.DB) error {

		path := ctx.RequestURI

		data := Data{}
		err := c.db.Where("path = ?", path).First(&data).Error
		fmt.Println(err)
		if err != nil {
			data = Data{
				ID:   uuid.NewV4(),
				Path: ctx.RequestURI,
				Data: workitem.Fields(ctx.Payload),
			}
			err := c.db.Create(&data).Error
			if err != nil {
				goa.LogError(ctx, "error adding data", "error", err.Error())
				return ctx.InternalServerError()
			}
		} else {
			err := c.db.Model(&data).Update("data", workitem.Fields(ctx.Payload)).Error
			if err != nil {
				goa.LogError(ctx, "error updating data", "error", err.Error())
				return ctx.InternalServerError()
			}
		}
		return ctx.NoContent()
	})
}
Example #2
0
// Run makes the HTTP request corresponding to the CreateBottleCommand command.
func (cmd *CreateBottleCommand) Run(c *client.Client, args []string) error {
	var path string
	if len(args) > 0 {
		path = args[0]
	} else {
		path = "/bottles"
	}
	var payload client.CreateBottlePayload
	if cmd.Payload != "" {
		err := json.Unmarshal([]byte(cmd.Payload), &payload)
		if err != nil {
			return fmt.Errorf("failed to deserialize payload: %s", err)
		}
	}
	logger := goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
	ctx := goa.WithLogger(context.Background(), logger)
	resp, err := c.CreateBottle(ctx, path, &payload, cmd.ContentType)
	if err != nil {
		goa.LogError(ctx, "failed", "err", err)
		return err
	}

	goaclient.HandleResponse(c.Client, resp, cmd.PrettyPrint)
	return nil
}
Example #3
0
// ErrorHandler turns a Go error into an HTTP response. It should be placed in the middleware chain
// below the logger middleware so the logger properly logs the HTTP response. ErrorHandler
// understands instances of goa.Error and returns the status and response body embodied in them,
// it turns other Go error types into a 500 internal error response.
// If verbose is false the details of internal errors is not included in HTTP responses.
func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware {
	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			e := h(ctx, rw, req)
			if e == nil {
				return nil
			}

			status := http.StatusInternalServerError
			var respBody interface{}
			if err, ok := e.(*goa.Error); ok {
				status = err.Status
				respBody = err
				goa.ContextResponse(ctx).ErrorCode = err.Code
				rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
			} else {
				respBody = e.Error()
				rw.Header().Set("Content-Type", "text/plain")
			}
			if status >= 500 && status < 600 {
				reqID := ctx.Value(reqIDKey)
				if reqID == nil {
					reqID = shortID()
					ctx = context.WithValue(ctx, reqIDKey, reqID)
				}
				goa.LogError(ctx, "uncaught error", "id", reqID, "msg", respBody)
				if !verbose {
					rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
					respBody = goa.ErrInternal("internal error [%s]", reqID)
				}
			}
			return service.Send(ctx, status, respBody)
		}
	}
}
Example #4
0
// Do wraps the underlying http client Do method and adds logging.
// The logger should be in the context.
func (c *Client) Do(ctx context.Context, req *http.Request) (*http.Response, error) {
	// TODO: setting the request ID should be done via client middleware. For now only set it if the
	// caller provided one in the ctx.
	if ctxreqid := ContextRequestID(ctx); ctxreqid != "" {
		req.Header.Set("X-Request-Id", ctxreqid)
	}
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	startedAt := time.Now()
	ctx, id := ContextWithRequestID(ctx)
	goa.LogInfo(ctx, "started", "id", id, req.Method, req.URL.String())
	if c.Dump {
		c.dumpRequest(ctx, req)
	}
	resp, err := c.Doer.Do(ctx, req)
	if err != nil {
		goa.LogError(ctx, "failed", "err", err)
		return nil, err
	}
	goa.LogInfo(ctx, "completed", "id", id, "status", resp.StatusCode, "time", time.Since(startedAt).String())
	if c.Dump {
		c.dumpResponse(ctx, resp)
	}
	return resp, err
}
Example #5
0
// Refresh makes a OAuth2 refresh access token request.
func (s *OAuth2Signer) Refresh(ctx context.Context) error {
	url := fmt.Sprintf(s.RefreshURLFormat, s.RefreshToken)
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	id := shortID()
	goa.LogInfo(ctx, "refresh", "id", id, "url", fmt.Sprintf(s.RefreshURLFormat, "*****"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		goa.LogError(ctx, "failed", "id", id, "err", err)
		return err
	}
	goa.LogInfo(ctx, "completed", "id", id, "status", resp.Status)
	defer resp.Body.Close()
	var r oauth2RefreshResponse
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read response body: %s", err)
	}
	err = json.Unmarshal(respBody, &r)
	if err != nil {
		return fmt.Errorf("failed to decode refresh request response: %s", err)
	}
	s.accessToken = r.AccessToken
	if r.ExpiresIn > 0 {
		s.expiresAt = time.Now().Add(time.Duration(r.ExpiresIn) * time.Second)
		goa.LogInfo(ctx, "refreshed", "expires", s.expiresAt)
	}
	if r.RefreshToken != "" {
		s.RefreshToken = r.RefreshToken
	}
	return nil
}
Example #6
0
// Dump request if needed.
func (c *Client) dumpRequest(ctx context.Context, req *http.Request) {
	reqBody, err := dumpReqBody(req)
	if err != nil {
		goa.LogError(ctx, "Failed to load request body for dump", "err", err.Error())
	}
	goa.LogInfo(ctx, "request headers", headersToSlice(req.Header)...)
	if reqBody != nil {
		goa.LogInfo(ctx, "request", "body", string(reqBody))
	}
}
Example #7
0
// Create creates a new record.
func (m *GormAreaRepository) Create(ctx context.Context, u *Area) error {
	defer goa.MeasureSince([]string{"goa", "db", "area", "create"}, time.Now())

	u.ID = uuid.NewV4()

	err := m.db.Create(u).Error
	if err != nil {
		goa.LogError(ctx, "error adding Area", "error", err.Error())
		return err
	}

	return nil
}
Example #8
0
// Run downloads files with given paths.
func (cmd *DownloadCommand) Run(c *client.Client, args []string) error {
	var (
		fnf func(context.Context, string) (int64, error)
		fnd func(context.Context, string, string) (int64, error)

		rpath   = args[0]
		outfile = cmd.OutFile
		logger  = goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
		ctx     = goa.WithLogger(context.Background(), logger)
		err     error
	)

	if rpath[0] != '/' {
		rpath = "/" + rpath
	}
	if rpath == "/swagger.json" {
		fnf = c.DownloadSwaggerJSON
		if outfile == "" {
			outfile = "swagger.json"
		}
		goto found
	}
	if strings.HasPrefix(rpath, "/swagger-ui/") {
		fnd = c.DownloadSwaggerUI
		rpath = rpath[12:]
		if outfile == "" {
			_, outfile = path.Split(rpath)
		}
		goto found
	}
	return fmt.Errorf("don't know how to download %s", rpath)
found:
	ctx = goa.WithLogContext(ctx, "file", outfile)
	if fnf != nil {
		_, err = fnf(ctx, outfile)
	} else {
		_, err = fnd(ctx, rpath, outfile)
	}
	if err != nil {
		goa.LogError(ctx, "failed", "err", err)
		return err
	}

	return nil
}
Example #9
0
// Run makes the HTTP request corresponding to the ShowBottleCommand command.
func (cmd *ShowBottleCommand) Run(c *client.Client, args []string) error {
	var path string
	if len(args) > 0 {
		path = args[0]
	} else {
		path = fmt.Sprintf("/bottles/%v", cmd.ID)
	}
	logger := goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
	ctx := goa.WithLogger(context.Background(), logger)
	resp, err := c.ShowBottle(ctx, path)
	if err != nil {
		goa.LogError(ctx, "failed", "err", err)
		return err
	}

	goaclient.HandleResponse(c.Client, resp, cmd.PrettyPrint)
	return nil
}
Example #10
0
// Do wraps the underlying http client Do method and adds logging.
// The logger should be in the context.
func (c *Client) Do(ctx context.Context, req *http.Request) (*http.Response, error) {
	req.Header.Set("User-Agent", c.UserAgent)
	startedAt := time.Now()
	id := shortID()
	goa.LogInfo(ctx, "started", "id", id, req.Method, req.URL.String())
	if c.Dump {
		c.dumpRequest(ctx, req)
	}
	resp, err := c.Client.Do(req)
	if err != nil {
		goa.LogError(ctx, "failed", "err", err)
		return nil, err
	}
	goa.LogInfo(ctx, "completed", "id", id, "status", resp.StatusCode, "time", time.Since(startedAt).String())
	if c.Dump {
		c.dumpResponse(ctx, resp)
	}
	return resp, err
}
Example #11
0
// ErrorHandler turns a Go error into an HTTP response. It should be placed in the middleware chain
// below the logger middleware so the logger properly logs the HTTP response. ErrorHandler
// understands instances of goa.ServiceError and returns the status and response body embodied in
// them, it turns other Go error types into a 500 internal error response.
// If verbose is false the details of internal errors is not included in HTTP responses.
// If you use github.com/pkg/errors then wrapping the error will allow a trace to be printed to the logs
func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware {
	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			e := h(ctx, rw, req)
			if e == nil {
				return nil
			}
			cause := errors.Cause(e)
			status := http.StatusInternalServerError
			var respBody interface{}
			if err, ok := cause.(goa.ServiceError); ok {
				status = err.ResponseStatus()
				respBody = err
				goa.ContextResponse(ctx).ErrorCode = err.Token()
				rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
			} else {
				respBody = e.Error()
				rw.Header().Set("Content-Type", "text/plain")
			}
			if status >= 500 && status < 600 {
				reqID := ctx.Value(reqIDKey)
				if reqID == nil {
					reqID = shortID()
					ctx = context.WithValue(ctx, reqIDKey, reqID)
				}
				goa.LogError(ctx, "uncaught error", "err", fmt.Sprintf("%+v", e), "id", reqID, "msg", respBody)
				if !verbose {
					rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
					msg := fmt.Sprintf("%s [%s]", http.StatusText(http.StatusInternalServerError), reqID)
					respBody = goa.ErrInternal(msg)
					// Preserve the ID of the original error as that's what gets logged, the client
					// received error ID must match the original
					if origErrID := goa.ContextResponse(ctx).ErrorCode; origErrID != "" {
						respBody.(*goa.ErrorResponse).ID = origErrID
					}
				}
			}
			return service.Send(ctx, status, respBody)
		}
	}
}
Example #12
0
File: jwt.go Project: ajoulie/goa
// New returns a middleware to be used with the JWTSecurity DSL definitions of goa.  It supports the
// scopes claim in the JWT and ensures goa-defined Security DSLs are properly validated.
//
// The steps taken by the middleware are:
//
//     1. Validate the "Bearer" token present in the "Authorization" header against the key(s)
//        given to New
//     2. If scopes are defined in the design for the action validate them against the "scopes" JWT
//        claim
//
// The `exp` (expiration) and `nbf` (not before) date checks are validated by the JWT library.
//
// validationKeys can be one of these:
//
//     * a single string
//     * a single []byte
//     * a list of string
//     * a list of []byte
//     * a single rsa.PublicKey
//     * a list of rsa.PublicKey
//
// The type of the keys determine the algorithms that will be used to do the check.  The goal of
// having lists of keys is to allow for key rotation, still check the previous keys until rotation
// has been completed.
//
// You can define an optional function to do additional validations on the token once the signature
// and the claims requirements are proven to be valid.  Example:
//
//    validationHandler, _ := goa.NewMiddleware(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
//        token := jwt.ContextJWT(ctx)
//        if val, ok := token.Claims["is_uncle"].(string); !ok || val != "ben" {
//            return jwt.ErrJWTError.Errorf("you are not uncle ben's")
//        }
//    })
//    app.MyJWTSecurity.Use(jwt.New("secret", validationHandler))
//
func New(validationKeys interface{}, validationFunc goa.Middleware) goa.JWTSecurityConfigFunc {
	return func(scheme *goa.JWTSecurity, getScopes func(context.Context) []string) goa.Middleware {
		var algo string
		var rsaKeys []*rsa.PublicKey
		var hmacKeys []string

		switch keys := validationKeys.(type) {
		case []*rsa.PublicKey:
			rsaKeys = keys
			algo = "RS"
		case *rsa.PublicKey:
			rsaKeys = []*rsa.PublicKey{keys}
			algo = "RS"
		case string:
			hmacKeys = []string{keys}
			algo = "HS"
		case []string:
			hmacKeys = keys
			algo = "HS"
		default:
			panic("invalid parameter to `jwt.New()`, only accepts *rsa.publicKey, []*rsa.PublicKey (for RSA-based algorithms) or a signing secret string (for HS algorithms)")
		}

		return func(nextHandler goa.Handler) goa.Handler {
			return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
				// TODO: implement the QUERY string handler too
				if scheme.In != goa.LocHeader {
					return fmt.Errorf("whoops, security scheme with in = %q not supported", scheme.In)
				}

				val := req.Header.Get(scheme.Name)
				if val == "" {
					return ErrJWTError("missing header %q", scheme.Name)
				}

				if !strings.HasPrefix(strings.ToLower(val), "bearer ") {
					return ErrJWTError("invalid or malformed %q header, expected 'Authorization: Bearer JWT-token...'", val)
				}

				incomingToken := strings.Split(val, " ")[1]

				var token *jwt.Token
				var err error
				switch algo {
				case "RS":
					token, err = validateRSAKeys(rsaKeys, algo, incomingToken)
				case "HS":
					token, err = validateHMACKeys(hmacKeys, algo, incomingToken)
				default:
					panic("how did this happen ? unsupported algo in jwt middleware")
				}
				if err != nil {
					return ErrJWTError("JWT validation failed")
				}

				scopesInClaim, scopesInClaimList, err := parseClaimScopes(token)
				if err != nil {
					goa.LogError(ctx, err.Error())
					return ErrJWTError(err)
				}

				requiredScopes := getScopes(ctx)

				for _, scope := range requiredScopes {
					if !scopesInClaim[scope] {
						return ErrJWTError("authorization failed: required 'scopes' not present in JWT claim").Meta("required_scopes", requiredScopes, "scopes_in_claim", scopesInClaimList)
					}
				}

				ctx = context.WithValue(ctx, jwtKey, token)
				if validationFunc != nil {
					nextHandler = validationFunc(nextHandler)
				}
				return nextHandler(ctx, rw, req)
			}
		}
	}
}
Example #13
0
	. "github.com/onsi/gomega"
	"golang.org/x/net/context"
)

var _ = Describe("Info", func() {
	Context("with a nil Log", func() {
		It("doesn't log and doesn't crash", func() {
			Ω(func() { goa.LogInfo(context.Background(), "foo", "bar") }).ShouldNot(Panic())
		})
	})
})

var _ = Describe("Error", func() {
	Context("with a nil Log", func() {
		It("doesn't log and doesn't crash", func() {
			Ω(func() { goa.LogError(context.Background(), "foo", "bar") }).ShouldNot(Panic())
		})
	})
})

var _ = Describe("LogAdapter", func() {
	Context("with a valid Log", func() {
		var logger goa.LogAdapter
		const msg = "message"
		data := []interface{}{"data", "foo"}

		var out bytes.Buffer

		BeforeEach(func() {
			stdlogger := log.New(&out, "", log.LstdFlags)
			logger = goa.NewLogger(stdlogger)
Example #14
0
File: jwt.go Project: smessier/goa
// New returns a middleware to be used with the JWTSecurity DSL definitions of goa.  It supports the
// scopes claim in the JWT and ensures goa-defined Security DSLs are properly validated.
//
// The steps taken by the middleware are:
//
//     1. Validate the "Bearer" token present in the "Authorization" header against the key(s)
//        given to New
//     2. If scopes are defined in the design for the action validate them against the "scopes" JWT
//        claim
//
// The `exp` (expiration) and `nbf` (not before) date checks are validated by the JWT library.
//
// validationKeys can be one of these:
//
//     * a single []byte
//     * a single string
//     * a slice of []byte
//     * a slice of string
//     * a single *rsa.PublicKey
//     * a slice of *rsa.PublicKey
//
// Keys of type string or []byte are interepreted according to the signing method defined in the JWT
// token (HMAC, RSA, etc.).
//
// You can define an optional function to do additional validations on the token once the signature
// and the claims requirements are proven to be valid.  Example:
//
//    validationHandler, _ := goa.NewMiddleware(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
//        token := jwt.ContextJWT(ctx)
//        if val, ok := token.Claims["is_uncle"].(string); !ok || val != "ben" {
//            return jwt.ErrJWTError("you are not uncle ben's")
//        }
//    })
//
// Mount the middleware with the generated UseXX function where XX is the name of the scheme as
// defined in the design, e.g.:
//
//    jwtResolver, _ := jwt.NewSimpleResolver("secret")
//    app.UseJWT(jwt.New(jwtResolver, validationHandler, app.NewJWTSecurity()))
//
func New(resolver KeyResolver, validationFunc goa.Middleware, scheme *goa.JWTSecurity) goa.Middleware {
	return func(nextHandler goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			// TODO: implement the QUERY string handler too
			if scheme.In != goa.LocHeader {
				return fmt.Errorf("whoops, security scheme with location (in) %q not supported", scheme.In)
			}
			val := req.Header.Get(scheme.Name)
			if val == "" {
				return ErrJWTError(fmt.Sprintf("missing header %q", scheme.Name))
			}

			if !strings.HasPrefix(strings.ToLower(val), "bearer ") {
				return ErrJWTError(fmt.Sprintf("invalid or malformed %q header, expected 'Authorization: Bearer JWT-token...'", val))
			}

			incomingToken := strings.Split(val, " ")[1]

			var (
				rsaKeys  []*rsa.PublicKey
				hmacKeys [][]byte
				keys     = resolver.SelectKeys(req)
			)
			{
				for _, key := range keys {
					switch k := key.(type) {
					case *rsa.PublicKey:
						rsaKeys = append(rsaKeys, k)
					case []byte:
						hmacKeys = append(hmacKeys, k)
					case string:
						hmacKeys = append(hmacKeys, []byte(k))
					}
				}
			}
			var (
				token     *jwt.Token
				err       error
				validated = false
			)

			if len(rsaKeys) > 0 {
				token, err = validateRSAKeys(rsaKeys, "RS", incomingToken)
				if err == nil {
					validated = true
				}
			}

			if !validated && len(hmacKeys) > 0 {
				token, err = validateHMACKeys(hmacKeys, "HS", incomingToken)
				if err == nil {
					validated = true
				}
			}

			if !validated {
				return ErrJWTError("JWT validation failed")
			}

			scopesInClaim, scopesInClaimList, err := parseClaimScopes(token)
			if err != nil {
				goa.LogError(ctx, err.Error())
				return ErrJWTError(err)
			}

			requiredScopes := goa.ContextRequiredScopes(ctx)

			for _, scope := range requiredScopes {
				if !scopesInClaim[scope] {
					msg := "authorization failed: required 'scopes' not present in JWT claim"
					return ErrJWTError(msg, "required", requiredScopes, "scopes", scopesInClaimList)
				}
			}

			ctx = WithJWT(ctx, token)
			if validationFunc != nil {
				nextHandler = validationFunc(nextHandler)
			}
			return nextHandler(ctx, rw, req)
		}
	}
}