Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions app/controlplane/configs/config.devel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ data:

# Development credentials for the SSO authentication roundtrip
auth:
dev_user: ${DEV_USER:}
oidc:
domain: ${DEX_DOMAIN:http://0.0.0.0:5556/dex}
client_id: "chainloop-dev"
Expand Down
143 changes: 77 additions & 66 deletions app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ message Auth {
string cas_robot_account_private_key_path = 4;
OIDC oidc = 6;

// Generates an initial user. Use only for development purposes
string dev_user = 7;

message OIDC {
string domain = 1;
string client_id = 2;
Expand Down
36 changes: 33 additions & 3 deletions app/controlplane/internal/service/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/jwt/user"
"github.com/chainloop-dev/chainloop/internal/oauth"
sl "github.com/chainloop-dev/chainloop/pkg/servicelogger"
"github.com/go-kratos/kratos/v2/log"
"golang.org/x/oauth2"
)

Expand All @@ -52,7 +53,9 @@ const (
// default
shortLivedDuration = 10 * time.Second
// opt-in
logLivedDuration = 24 * time.Hour
longLivedDuration = 24 * time.Hour
// dev only
devUserDuration = 30 * longLivedDuration
)

type oauthHandler struct {
Expand Down Expand Up @@ -90,8 +93,16 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC
return nil, fmt.Errorf("failed to create OIDC authenticator: %w", err)
}

svc := newService(opts...)
if authConfig.DevUser != "" {
err := generateAndLogDevUser(userUC, svc.log, authConfig)
if err != nil {
return nil, fmt.Errorf("failed to create development user: %w", err)
}
}

return &AuthService{
service: newService(opts...),
service: svc,
authenticator: authInst,
userUseCase: userUC,
orgUseCase: orgUC,
Expand Down Expand Up @@ -231,7 +242,7 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) (
}

if longLived.Value == "true" {
expiration = logLivedDuration
expiration = longLivedDuration
}

// Generate user token
Expand Down Expand Up @@ -338,6 +349,25 @@ func setOauthCookie(w http.ResponseWriter, name, value string) {
http.SetCookie(w, &http.Cookie{Name: name, Value: value, Path: "/", Expires: time.Now().Add(5 * time.Minute)})
}

func generateAndLogDevUser(userUC *biz.UserUseCase, log *log.Helper, authConfig *conf.Auth) error {
// Create user if needed
u, err := userUC.FindOrCreateByEmail(context.Background(), authConfig.DevUser)
if err != nil {
return sl.LogAndMaskErr(err, log)
}

// Generate user token
userToken, err := generateUserJWT(u.ID, authConfig.GeneratedJwsHmacSecret, devUserDuration)
if err != nil {
return sl.LogAndMaskErr(err, log)
}

log.Info("******************* DEVELOPMENT USER TOKEN *******************")
log.Infof("Use chainloop 'auth login --skip-browser' and paste this token to start a headless session: %s", userToken)

return nil
}

// DeleteAccount deletes an account
func (svc *AuthService) DeleteAccount(ctx context.Context, _ *pb.AuthServiceDeleteAccountRequest) (*pb.AuthServiceDeleteAccountResponse, error) {
user, err := requireCurrentUser(ctx)
Expand Down
19 changes: 17 additions & 2 deletions devel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,25 @@ Configure the CLI to point to the local control plane and CAS services.
chainloop config save --insecure --control-plane localhost:9000 --artifact-cas localhost:9001
```

and login
A new user and token has been created for you during bootstrap. An authentication token is available in the service logs (note that this is deactivated in production mode).
Look for `DEVELOPMENT USER TOKEN` message in the container logs:
```
> docker compose -f compose.labs.yaml logs control-plane | grep -A 1 "DEVELOPMENT USER TOKEN"
control-plane-1 | {"level":"info","ts":1724772518.38039,"component":"service","msg":"******************* DEVELOPMENT USER TOKEN *******************"}
control-plane-1 | {"level":"info","ts":1724772518.3804584,"component":"service","msg":"Use chainloop 'auth login --skip-browser' and paste this token to start a headless session: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNzc4ZmExMzAtNjUzOS00ZTVmLThlYmYtMGQyZTkxYjRlNmM5IiwiaXNzIjoiY3AuY2hhaW5sb29wIiwiYXVkIjpbInVzZXItYXV0aC5jaGFpbmxvb3AiXSwiZXhwIjoxNzI3MzY0NTE4fQ.nyQtlR3bpc0VIna_UIKlXcx62gwG1dbuhkVm22fEXv4"}
```

To authenticate, run this command and paste the token from the logs.
```
chainloop --insecure auth login
> chainloop --insecure auth login --skip-browser
WRN API contacted in insecure mode
WRN Both user credentials and $CHAINLOOP_TOKEN set. Ignoring $CHAINLOOP_TOKEN.
To authenticate, click on the following link and paste the result back here

http://0.0.0.0:8000/auth/login?long-lived=true

Enter Token:
INF login successful!
```

you are now ready to use the CLI and follow the [quickstart guide](https://docs.chainloop.dev/quickstart)
3 changes: 3 additions & 0 deletions devel/compose.labs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ services:
CP_FILE_CA_CERT_PATH: /devkeys/ca.pub
CP_FILE_CA_KEY_PATH: /devkeys/ca.pem
CP_CAS_KEY_PATH: /devkeys/cas.pem
CP_DEV_USER: john@chainloop.local
volumes:
# main configuration
- ../app/controlplane/configs:/data/conf
Expand All @@ -32,6 +33,8 @@ services:
- 9000:9000
- 8000:8000
depends_on:
dex:
condition: service_started
vault:
condition: service_started
db-init:
Expand Down