diff --git a/cli/cdsctl/login.go b/cli/cdsctl/login.go index 4b78422b11..687122942f 100644 --- a/cli/cdsctl/login.go +++ b/cli/cdsctl/login.go @@ -21,6 +21,7 @@ import ( var loginCmd = cli.Command{ Name: "login", Short: "Login to CDS", + Long: "For admin signup with LDAP driver, INIT_TOKEN environment variable must be set.", Example: `Use it with 'eval' and 'env' flag to set environment variable: eval $(cds login -H API_URL -u USERNAME -p PASSWORD --env)`, Flags: []cli.Flag{ { @@ -47,11 +48,6 @@ var loginCmd = cli.Command{ Name: "password", ShortHand: "p", }, - { - Name: "init-token", - Usage: "A CDS init token that can be used for first connection", - ShortHand: "i", - }, { Name: "token", Usage: "A CDS token that can be used to login with a builtin auth driver.", @@ -60,7 +56,7 @@ var loginCmd = cli.Command{ } func login() *cobra.Command { - return cli.NewCommand(loginCmd, loginRun, nil, cli.CommandWithoutExtraFlags) + return cli.NewCommand(loginCmd, loginRun, cli.SubCommands{loginVerify()}, cli.CommandWithoutExtraFlags) } func loginRun(v cli.Values) error { @@ -116,7 +112,7 @@ func loginRun(v cli.Values) error { if noInteractive { return fmt.Errorf("Cannot signin with %s driver in no interactive mode", driverType) } - req, err = loginRunExternal(v, driverType, apiURL) + return loginRunExternal(v, driverType, apiURL) } if err != nil { return err @@ -124,7 +120,7 @@ func loginRun(v cli.Values) error { // For first connection ask for an optional init token if drivers.IsFirstConnection { - initToken := v.GetString("init-token") + initToken := os.Getenv("INIT_TOKEN") if initToken != "" { req["init_token"] = initToken } @@ -196,36 +192,28 @@ func loginRunBuiltin(v cli.Values) (sdk.AuthConsumerSigninRequest, error) { return req, nil } -func loginRunExternal(v cli.Values, consumerType sdk.AuthConsumerType, apiURL string) (sdk.AuthConsumerSigninRequest, error) { - req := sdk.AuthConsumerSigninRequest{} - +func loginRunExternal(v cli.Values, consumerType sdk.AuthConsumerType, apiURL string) error { client := cdsclient.New(cdsclient.Config{ Host: apiURL, Verbose: v.GetBool("verbose"), }) config, err := client.ConfigUser() if err != nil { - return req, err + return err } askSigninURI, err := url.Parse(config.URLUI + "/auth/ask-signin/" + string(consumerType) + "?origin=cdsctl") if err != nil { - return req, fmt.Errorf("cannot parse given api uri: %v", err) + return fmt.Errorf("cannot parse given api uri: %v", err) } fmt.Println("cdsctl: Opening the browser to login or control-c to abort") fmt.Println(" >\tWarning: If browser does not open, visit") fmt.Println(" >\t" + cli.Green("%s", askSigninURI.String())) browser.OpenURL(askSigninURI.String()) // nolint + fmt.Println(" >\tPlease follow instructions given on your browser to finish login.") - token := cli.AskPassword("Token") - splittedToken := strings.Split(token, ":") - if len(splittedToken) != 2 { - return req, fmt.Errorf("Invalid given token") - } - req["state"], req["code"] = splittedToken[0], splittedToken[1] - - return req, nil + return nil } func doAfterLogin(client cdsclient.Interface, v cli.Values, apiURL string, driverType sdk.AuthConsumerType, res sdk.AuthConsumerSigninResponse) error { @@ -424,3 +412,76 @@ func writeConfigFile(configFile string, content *bytes.Buffer) error { } return nil } + +func loginVerify() *cobra.Command { + return cli.NewCommand(loginVerifyCmd, loginVerifyFunc, nil, cli.CommandWithoutExtraFlags) +} + +var loginVerifyCmd = cli.Command{ + Name: "verify", + Long: "For admin signup INIT_TOKEN environment variable must be set.", + Hidden: true, + Args: []cli.Arg{ + { + Name: "api-url", + AllowEmpty: false, + }, + { + Name: "driver-type", + AllowEmpty: false, + }, + { + Name: "token", + AllowEmpty: false, + }, + }, +} + +func loginVerifyFunc(v cli.Values) error { + apiURL := v.GetString("api-url") + + // Load all drivers from given CDS instance + client := cdsclient.New(cdsclient.Config{ + Host: apiURL, + Verbose: os.Getenv("CDS_VERBOSE") == "true", + }) + drivers, err := client.AuthDriverList() + if err != nil { + return fmt.Errorf("Cannot list auth drivers: %v", err) + } + if len(drivers.Drivers) == 0 { + return fmt.Errorf("No authentication driver configured") + } + + driverType := sdk.AuthConsumerType(v.GetString("driver-type")) + if !driverType.IsValidExternal() { + return fmt.Errorf("Invalid given driver type: %s", driverType) + } + + token := v.GetString("token") + splittedToken := strings.Split(token, ":") + if len(splittedToken) != 2 { + return fmt.Errorf("Invalid given token") + } + + req := sdk.AuthConsumerSigninRequest{ + "state": splittedToken[0], + "code": splittedToken[1], + } + + // For first connection ask for an optional init token + if drivers.IsFirstConnection { + initToken := os.Getenv("INIT_TOKEN") + if initToken != "" { + req["init_token"] = initToken + } + } + + // Send signin request + res, err := client.AuthConsumerSignin(driverType, req) + if err != nil { + return fmt.Errorf("cannot signin: %v", err) + } + + return doAfterLogin(client, v, apiURL, driverType, res) +} diff --git a/cli/cdsctl/signup.go b/cli/cdsctl/signup.go index 07a0bc6856..0187917d11 100644 --- a/cli/cdsctl/signup.go +++ b/cli/cdsctl/signup.go @@ -125,7 +125,8 @@ func signupFunc(v cli.Values) error { var signupVerifyCmd = cli.Command{ Name: "verify", - Short: "Verify local CDS signup.\nFor admin signup INIT_TOKEN environment variable must be set", + Short: "Verify local CDS signup.", + Long: "For admin signup INIT_TOKEN environment variable must be set.", Args: []cli.Arg{ { Name: "token", diff --git a/engine/api/router.go b/engine/api/router.go index 9cd07d48b9..9fb429ab8d 100644 --- a/engine/api/router.go +++ b/engine/api/router.go @@ -512,7 +512,7 @@ func EnableTracing() HandlerConfigParam { // NotFoundHandler is called by default by Mux is any matching handler has been found func NotFoundHandler(w http.ResponseWriter, req *http.Request) { - service.WriteError(w, req, sdk.ErrNotFound) + service.WriteError(w, req, sdk.WithStack(sdk.ErrNotFound)) } // StatusPanic returns router status. If nbPanic > 30 -> Alert, if nbPanic > 0 -> Warn diff --git a/ui/src/app/model/config.model.ts b/ui/src/app/model/config.model.ts deleted file mode 100644 index e17a0aff6b..0000000000 --- a/ui/src/app/model/config.model.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class Config { - url_api: string; - url_ui: string; -} - diff --git a/ui/src/app/service/config/config.service.ts b/ui/src/app/service/config/config.service.ts index 88dd49494f..38dbf45997 100644 --- a/ui/src/app/service/config/config.service.ts +++ b/ui/src/app/service/config/config.service.ts @@ -1,22 +1,16 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Config} from 'app/model/config.model'; -import {Observable} from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; /** * Service to get config */ @Injectable() export class ConfigService { - constructor(private _http: HttpClient) { } - /** - * Get the config (url api / url ui) - * @returns {Observable} - */ - getConfig(): Observable { - return this._http.get('/config/user'); + getConfig(): Observable { + return this._http.get('/config/user'); } } diff --git a/ui/src/app/views/auth/callback/callback.component.ts b/ui/src/app/views/auth/callback/callback.component.ts index 1c893156b0..911466d85c 100644 --- a/ui/src/app/views/auth/callback/callback.component.ts +++ b/ui/src/app/views/auth/callback/callback.component.ts @@ -3,6 +3,7 @@ import { NgForm } from '@angular/forms'; import { ActivatedRoute, DefaultUrlSerializer, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { AuthenticationService } from 'app/service/authentication/authentication.service'; +import { ConfigService } from 'app/service/services.module'; import { AutoUnsubscribe } from 'app/shared/decorator/autoUnsubscribe'; import { ToastService } from 'app/shared/toast/ToastService'; import { jws } from 'jsrsasign'; @@ -28,6 +29,7 @@ export class CallbackComponent implements OnInit { showInitTokenForm: boolean; consumerType: string; payloadData: any; + cmd: string; constructor( private _route: ActivatedRoute, @@ -35,7 +37,8 @@ export class CallbackComponent implements OnInit { private _toast: ToastService, private _translate: TranslateService, private _router: Router, - private _authenticationService: AuthenticationService + private _authenticationService: AuthenticationService, + private _configService: ConfigService ) { this.loading = true; } @@ -60,9 +63,12 @@ export class CallbackComponent implements OnInit { // If the origin is cdsctl, show the code and the state for copy if (this.payloadData && this.payloadData.origin === 'cdsctl') { - this.loading = false; - this.showCTL = true; - this._cd.markForCheck(); + this._configService.getConfig().subscribe(config => { + this.cmd = `cdsctl login verify ${config['url.api']} ${this.consumerType} ${this.state}:${this.code}` + this.loading = false; + this.showCTL = true; + this._cd.markForCheck(); + }) return; } diff --git a/ui/src/app/views/auth/callback/callback.html b/ui/src/app/views/auth/callback/callback.html index e097b391e7..0c6a436633 100644 --- a/ui/src/app/views/auth/callback/callback.html +++ b/ui/src/app/views/auth/callback/callback.html @@ -15,11 +15,11 @@
- +
- +
@@ -50,7 +50,8 @@
-
@@ -59,4 +60,4 @@ - + \ No newline at end of file diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index af910c428c..381255e251 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -4,7 +4,8 @@ "auth_button_signin_with": "Sign in with {{consumer}}", "auth_value_copied": "Value copied", "auth_message_init_token": "If you just generated the CDS configuration you can give an optional init token.", - "auth_message_copy": "You can now copy this parameters to your terminal then close this tab.", + "auth_message_command": "Command", + "auth_message_copy": "You can now copy this command to your terminal to finish login then close this tab.", "auth_message_copy_signin_token": "You can now use this token to signin with the consumer.", "auth_callback_missing_param": "One or more params are missing to continue. You can try to sign in again.", "auth_callback_error": "A error occurred. You can try to sign in again.", diff --git a/ui/src/assets/i18n/fr.json b/ui/src/assets/i18n/fr.json index 7350f1a512..21e1002de2 100644 --- a/ui/src/assets/i18n/fr.json +++ b/ui/src/assets/i18n/fr.json @@ -4,7 +4,8 @@ "auth_button_signin_with": "Se connecter avec {{consumer}}", "auth_value_copied": "La valeur a été copiée", "auth_message_init_token": "Si vous venez de générer la configuration de CDS, vous pouvez fournir la clé d'initialisation falculative.", - "auth_message_copy": "Vous pouvez maintenant copier ces paramètres dans votre terminal puis fermer cet onglet.", + "auth_message_command": "Commande", + "auth_message_copy": "Vous pouvez maintenant copier cette commande dans votre terminal pour terminer la connexion, puis fermer cet onglet.", "auth_message_copy_signin_token": "Vous pouvez maintenant utiliser ce token pour vous identifier avec le client.", "auth_callback_missing_param": "Un ou plusieurs paramètres sont manquants pour poursuivre. Vous pouvez essayer de vous connecter à nouveau.", "auth_callback_error": "Une erreur est seurvenue. Vous pouvez essayer de vous connecter à nouveau.",