Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 20 additions & 27 deletions api/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
package api

import (
"encoding/base64"
"fmt"
"net/http"

"github.com/gin-gonic/gin"
"github.com/go-vela/server/database"
"github.com/go-vela/server/router/middleware/token"
"github.com/go-vela/server/internal/token"
"github.com/go-vela/server/scm"
"github.com/go-vela/server/util"
"github.com/go-vela/types"
"github.com/go-vela/types/constants"
"github.com/go-vela/types/library"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -47,7 +46,7 @@ import (
// Set-Cookie:
// type: string
// schema:
// "$ref": "#/definitions/Login"
// "$ref": "#/definitions/Token"
// '307':
// description: Redirected for authentication
// '401':
Expand All @@ -65,6 +64,8 @@ import (
func Authenticate(c *gin.Context) {
var err error

tm := c.MustGet("token-manager").(*token.Manager)

// capture the OAuth state if present
oAuthState := c.Request.FormValue("state")

Expand Down Expand Up @@ -102,30 +103,15 @@ func Authenticate(c *gin.Context) {
u, err := database.FromContext(c).GetUserForName(newUser.GetName())
// create a new user account
if len(u.GetName()) == 0 || err != nil {
// create unique id for the user
uid, err := uuid.NewRandom()
if err != nil {
retErr := fmt.Errorf("unable to create UID for user %s: %w", u.GetName(), err)

util.HandleError(c, http.StatusServiceUnavailable, retErr)

return
}

// create the user account
u := new(library.User)
u.SetName(newUser.GetName())
u.SetToken(newUser.GetToken())
u.SetHash(
base64.StdEncoding.EncodeToString(
[]byte(uid.String()),
),
)
u.SetActive(true)
u.SetAdmin(false)

// compose jwt tokens for user
rt, at, err := token.Compose(c, u)
rt, at, err := tm.Compose(c, u)
if err != nil {
retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err)

Expand All @@ -148,7 +134,7 @@ func Authenticate(c *gin.Context) {
}

// return the jwt access token
c.JSON(http.StatusOK, library.Login{Token: &at})
c.JSON(http.StatusOK, library.Token{Token: &at})

return
}
Expand All @@ -158,7 +144,7 @@ func Authenticate(c *gin.Context) {
u.SetActive(true)

// compose jwt tokens for user
rt, at, err := token.Compose(c, u)
rt, at, err := tm.Compose(c, u)
if err != nil {
retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err)

Expand All @@ -181,7 +167,7 @@ func Authenticate(c *gin.Context) {
}

// return the user with their jwt access token
c.JSON(http.StatusOK, library.Login{Token: &at})
c.JSON(http.StatusOK, library.Token{Token: &at})
}

// swagger:operation GET /authenticate/web authenticate GetAuthenticateTypeWeb
Expand Down Expand Up @@ -289,7 +275,7 @@ func AuthenticateType(c *gin.Context) {
// '200':
// description: Successfully authenticated
// schema:
// "$ref": "#/definitions/Login"
// "$ref": "#/definitions/Token"
// '401':
// description: Unable to authenticate
// schema:
Expand Down Expand Up @@ -325,8 +311,15 @@ func AuthenticateToken(c *gin.Context) {

// We don't need refresh token for this scenario
// We only need access token and are configured based on the config defined
m := c.MustGet("metadata").(*types.Metadata)
at, err := token.CreateAccessToken(u, m.Vela.AccessTokenDuration)
tm := c.MustGet("token-manager").(*token.Manager)

// mint token options for access token
amto := &token.MintTokenOpts{
User: u,
TokenType: constants.UserAccessTokenType,
TokenDuration: tm.UserAccessTokenDuration,
}
at, err := tm.MintToken(amto)

if err != nil {
retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err)
Expand All @@ -335,5 +328,5 @@ func AuthenticateToken(c *gin.Context) {
}

// return the user with their jwt access token
c.JSON(http.StatusOK, library.Login{Token: &at})
c.JSON(http.StatusOK, library.Token{Token: &at})
}
96 changes: 95 additions & 1 deletion api/build.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Target Brands, Inc. All rights reserved.
// Copyright (c) 2023 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

Expand All @@ -14,6 +14,8 @@ import (
"strings"
"time"

"github.com/go-vela/server/internal/token"
"github.com/go-vela/server/router/middleware/claims"
"github.com/go-vela/server/router/middleware/org"

"github.com/go-vela/server/compiler"
Expand Down Expand Up @@ -1899,3 +1901,95 @@ func CancelBuild(c *gin.Context) {

c.JSON(http.StatusOK, b)
}

// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/token builds GetBuildToken
//
// Get a build token
//
// ---
// produces:
// - application/json
// parameters:
// - in: path
// name: repo
// description: Name of the repo
// required: true
// type: string
// - in: path
// name: org
// description: Name of the org
// required: true
// type: string
// - in: path
// name: build
// description: Build number
// required: true
// type: integer
// security:
// - ApiKeyAuth: []
// responses:
// '200':
// description: Successfully retrieved build token
// schema:
// "$ref": "#/definitions/Token"
// '400':
// description: Bad request
// schema:
// "$ref": "#/definitions/Error"
// '500':
// description: Unable to generate build token
// schema:
// "$ref": "#/definitions/Error"

// GetBuildToken represents the API handler to generate a build token.
func GetBuildToken(c *gin.Context) {
// capture middleware values
b := build.Retrieve(c)
o := org.Retrieve(c)
r := repo.Retrieve(c)
cl := claims.Retrieve(c)

// update engine logger with API metadata
//
// https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields
logrus.WithFields(logrus.Fields{
"build": b.GetNumber(),
"org": o,
"repo": r.GetName(),
"user": cl.Subject,
}).Infof("generating build token for build %s/%d", r.GetFullName(), b.GetNumber())

// if build is not in a pending state, then a build token should not be needed - bad request
if !strings.EqualFold(b.GetStatus(), constants.StatusPending) {
retErr := fmt.Errorf("unable to mint build token: build is not in pending state")
util.HandleError(c, http.StatusBadRequest, retErr)

return
}

// retrieve token manager from context
tm := c.MustGet("token-manager").(*token.Manager)

// set expiration to repo timeout plus configurable buffer
exp := (time.Duration(r.GetTimeout()) * time.Minute) + tm.BuildTokenBufferDuration

// set mint token options
bmto := &token.MintTokenOpts{
Hostname: cl.Subject,
BuildID: b.GetID(),
Repo: r.GetFullName(),
TokenType: constants.WorkerBuildTokenType,
TokenDuration: exp,
}

// mint token
bt, err := tm.MintToken(bmto)
if err != nil {
retErr := fmt.Errorf("unable to generate build token: %w", err)
util.HandleError(c, http.StatusInternalServerError, retErr)

return
}

c.JSON(http.StatusOK, library.Token{Token: &bt})
}
4 changes: 3 additions & 1 deletion api/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/gin-gonic/gin"
"github.com/go-vela/server/router/middleware/claims"
"github.com/go-vela/server/router/middleware/user"
"github.com/go-vela/server/scm"
"github.com/go-vela/server/secret"
Expand Down Expand Up @@ -485,6 +486,7 @@ func GetSecrets(c *gin.Context) {
// GetSecret gets a secret from the provided secrets service.
func GetSecret(c *gin.Context) {
// capture middleware values
cl := claims.Retrieve(c)
u := user.Retrieve(c)
e := util.PathParameter(c, "engine")
t := util.PathParameter(c, "type")
Expand Down Expand Up @@ -533,7 +535,7 @@ func GetSecret(c *gin.Context) {
}

// only allow workers to access the full secret with the value
if u.GetAdmin() && u.GetName() == "vela-worker" {
if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) {
c.JSON(http.StatusOK, secret)

return
Expand Down
13 changes: 8 additions & 5 deletions api/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
"fmt"
"net/http"

"github.com/go-vela/server/router/middleware/token"
"github.com/go-vela/server/internal/token"
"github.com/go-vela/server/router/middleware/auth"
"github.com/go-vela/server/util"

"github.com/go-vela/types/library"
Expand All @@ -29,7 +30,7 @@ import (
// '200':
// description: Successfully refreshed a token
// schema:
// "$ref": "#/definitions/Login"
// "$ref": "#/definitions/Token"
// '401':
// description: Unauthorized
// schema:
Expand All @@ -41,7 +42,7 @@ func RefreshAccessToken(c *gin.Context) {
// capture the refresh token
// TODO: move this into token package and do it internally
// since we are already passsing context
rt, err := token.RetrieveRefreshToken(c.Request)
rt, err := auth.RetrieveRefreshToken(c.Request)
if err != nil {
retErr := fmt.Errorf("refresh token error: %w", err)

Expand All @@ -50,8 +51,10 @@ func RefreshAccessToken(c *gin.Context) {
return
}

tm := c.MustGet("token-manager").(*token.Manager)

// validate the refresh token and return a new access token
newAccessToken, err := token.Refresh(c, rt)
newAccessToken, err := tm.Refresh(c, rt)
if err != nil {
retErr := fmt.Errorf("unable to refresh token: %w", err)

Expand All @@ -60,5 +63,5 @@ func RefreshAccessToken(c *gin.Context) {
return
}

c.JSON(http.StatusOK, library.Login{Token: &newAccessToken})
c.JSON(http.StatusOK, library.Token{Token: &newAccessToken})
}
Loading