2026-04-06 15:48:37 +05:30
// Copyright IBM Corp. 2020, 2026
2023-03-15 11:40:40 -04:00
// SPDX-License-Identifier: BUSL-1.1
package authenticate
import (
"errors"
"fmt"
"os"
"strings"
2026-10-12 10:33:41 -07:00
"repo.anhonesthost.net/CyberCoveLLC/threshold/api"
"repo.anhonesthost.net/CyberCoveLLC/threshold/api/authmethods"
"repo.anhonesthost.net/CyberCoveLLC/threshold/globals"
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/cmd/base"
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/types/scope"
2023-03-15 11:40:40 -04:00
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/mitchellh/cli"
"github.com/mitchellh/go-wordwrap"
"github.com/posener/complete"
)
var (
_ cli . Command = ( * PasswordCommand )( nil )
_ cli . CommandAutocomplete = ( * PasswordCommand )( nil )
)
type LdapCommand struct {
* base . Command
flagLoginName string
flagPassword string
2023-11-01 12:45:35 -07:00
parsedOpts base . Options
2023-03-15 11:40:40 -04:00
}
func ( c * LdapCommand ) Synopsis () string {
2026-10-12 10:20:06 -07:00
return wordwrap . WrapString ( "Invoke the ldap auth method to authenticate with Threshold" , base . TermWidth )
2023-03-15 11:40:40 -04:00
}
func ( c * LdapCommand ) Help () string {
return base . WrapForHelpText ([] string {
2026-10-12 10:20:06 -07:00
"Usage: threshold authenticate ldap [options] [args]" ,
2023-03-15 11:40:40 -04:00
"" ,
2026-10-12 10:20:06 -07:00
" Invoke the ldap auth method to authenticate the Threshold CLI. Example:" ,
2023-03-15 11:40:40 -04:00
"" ,
2026-10-12 10:20:06 -07:00
` $ threshold authenticate ldap -auth-method-id amldap_1234567890 -login-name foo` ,
2023-03-15 11:40:40 -04:00
"" ,
"" ,
}) + c . Flags (). Help ()
}
func ( c * LdapCommand ) Flags () * base . FlagSets {
set := c . FlagSet ( base . FlagSetHTTP | base . FlagSetClient | base . FlagSetOutputFormat )
f := set . NewFlagSet ( "Command Options" )
f . StringVar ( & base . StringVar {
Name : "login-name" ,
Target : & c . flagLoginName ,
EnvVar : envLoginName ,
Usage : "The login name corresponding to an account within the given auth method." ,
})
f . StringVar ( & base . StringVar {
Name : "password" ,
Target : & c . flagPassword ,
EnvVar : envPassword ,
Usage : "The password associated with the login name. If blank, the command will prompt for the password to be entered interactively in a non-echoing way. Otherwise, this can refer to a file on disk (file://) from which a password will be read or an env var (env://) from which the password will be read." ,
})
f . StringVar ( & base . StringVar {
Name : "auth-method-id" ,
2026-10-12 10:20:06 -07:00
EnvVar : "THRESHOLD_AUTH_METHOD_ID" ,
2023-03-15 11:40:40 -04:00
Target : & c . FlagAuthMethodId ,
Usage : "The auth-method resource to use for the operation." ,
})
2023-11-01 12:45:35 -07:00
if ! c . parsedOpts . WithSkipScopeIdFlag {
2023-03-15 11:40:40 -04:00
f . StringVar ( & base . StringVar {
Name : "scope-id" ,
2026-10-12 10:20:06 -07:00
EnvVar : "THRESHOLD_SCOPE_ID" ,
2023-03-15 11:40:40 -04:00
Target : & c . FlagScopeId ,
Usage : "The scope ID to use for the operation." ,
})
}
return set
}
func ( c * LdapCommand ) AutocompleteArgs () complete . Predictor {
return complete . PredictAnything
}
func ( c * LdapCommand ) AutocompleteFlags () complete . Flags {
return c . Flags (). Completions ()
}
func ( c * LdapCommand ) Run ( args [] string ) int {
2023-11-01 12:45:35 -07:00
c . parsedOpts = base . GetOpts ( c . Opts ... )
2023-03-15 11:40:40 -04:00
f := c . Flags ()
if err := f . Parse ( args ); err != nil {
c . PrintCliError ( err )
return base . CommandUserError
}
switch c . flagLoginName {
case "" :
var input string
fmt . Print ( "Please enter the login name: " )
_ , err := fmt . Scanln ( & input )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "An error occurred attempting to read the login name. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s" , err . Error ()))
return base . CommandUserError
}
c . flagLoginName = strings . TrimSpace ( input )
}
switch c . flagPassword {
case "" :
fmt . Print ( "Please enter the password (it will be hidden): " )
value , err := password . Read ( os . Stdin )
fmt . Print ( "\n" )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s" , err . Error ()))
return base . CommandUserError
}
c . flagPassword = strings . TrimSpace ( value )
default :
password , err := parseutil . MustParsePath ( c . flagPassword )
switch {
case err == nil :
case errors . Is ( err , parseutil . ErrNotParsed ):
c . UI . Error ( "Password flag must be used with env:// or file:// syntax or left empty for an interactive prompt" )
return base . CommandUserError
default :
c . UI . Error ( fmt . Sprintf ( "Error parsing password flag: %v" , err ))
return base . CommandUserError
}
c . flagPassword = password
}
client , err := c . Client ( base . WithNoTokenScope (), base . WithNoTokenValue ())
if c . WrapperCleanupFunc != nil {
defer func () {
if err := c . WrapperCleanupFunc (); err != nil {
c . PrintCliError ( fmt . Errorf ( "Error cleaning kms wrapper: %w" , err ))
}
}()
}
if err != nil {
c . PrintCliError ( fmt . Errorf ( "Error creating API client: %w" , err ))
return base . CommandCliError
}
aClient := authmethods . NewClient ( client )
// if auth method ID isn't passed on the CLI, try looking up the primary auth method ID
if c . FlagAuthMethodId == "" {
// if flag for scope is empty try looking up global
if c . FlagScopeId == "" {
c . FlagScopeId = scope . Global . String ()
}
pri , err := getPrimaryAuthMethodId ( c . Context , aClient , c . FlagScopeId , globals . LdapAuthMethodPrefix )
if err != nil {
c . PrintCliError ( err )
return base . CommandUserError
}
c . FlagAuthMethodId = pri
}
result , err := aClient . Authenticate ( c . Context , c . FlagAuthMethodId , "login" ,
map [ string ] any {
"login_name" : c . flagLoginName ,
"password" : c . flagPassword ,
})
if err != nil {
if apiErr := api . AsServerError ( err ); apiErr != nil {
c . PrintApiError ( apiErr , "Error from controller when performing authentication" )
return base . CommandApiError
}
c . PrintCliError ( fmt . Errorf ( "Error trying to perform authentication: %w" , err ))
return base . CommandCliError
}
2023-11-01 12:45:35 -07:00
return saveAndOrPrintToken ( c . Command , result , c . Opts ... )
2023-03-15 11:40:40 -04:00
}