Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature (cli/ldap/authenticate): use primary auth method if none is provided #2890

Merged
merged 5 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
24 changes: 24 additions & 0 deletions api/authmethods/option.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,30 @@ func DefaultLdapAuthMethodStartTls() Option {
}
}

func WithLdapAuthMethodState(inState string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
if !ok {
raw = interface{}(map[string]interface{}{})
}
val := raw.(map[string]interface{})
val["state"] = inState
o.postMap["attributes"] = val
}
}

func DefaultLdapAuthMethodState() Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
if !ok {
raw = interface{}(map[string]interface{}{})
}
val := raw.(map[string]interface{})
val["state"] = nil
o.postMap["attributes"] = val
}
}

func WithLdapAuthMethodUpnDomain(inUpnDomain string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
Expand Down
570 changes: 286 additions & 284 deletions internal/auth/ldap/store/ldap.pb.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions internal/cmd/commands/authenticate/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/auth/ldap"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/cmd/base"
Expand Down Expand Up @@ -109,6 +110,10 @@ func (c *Command) Run(args []string) int {
cmd := OidcCommand{Command: c.Command, Opts: []common.Option{common.WithSkipScopeIdFlag(true)}}
cmd.Run([]string{})

case strings.HasPrefix(c.FlagAuthMethodId, ldap.AuthMethodPrefix):
cmd := LdapCommand{Command: c.Command, Opts: []common.Option{common.WithSkipScopeIdFlag(true)}}
cmd.Run([]string{})

default:
c.PrintCliError(fmt.Errorf("The primary auth method was of an unsupported type. The given ID was %s; only 'ampw' (password) and 'amoidc' (OIDC) auth method prefixes are supported.", c.FlagAuthMethodId))
return cli.RunResultHelp
Expand Down
56 changes: 48 additions & 8 deletions internal/cmd/commands/authenticate/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import (

"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/auth/ldap"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/mitchellh/cli"
Expand All @@ -26,6 +29,8 @@ type LdapCommand struct {

flagLoginName string
flagPassword string
Opts []common.Option
parsedOpts *common.Options
}

func (c *LdapCommand) Synopsis() string {
Expand Down Expand Up @@ -69,6 +74,15 @@ func (c *LdapCommand) Flags() *base.FlagSets {
Usage: "The auth-method resource to use for the operation.",
})

if c.parsedOpts == nil || !c.parsedOpts.WithSkipScopeIdFlag {
f.StringVar(&base.StringVar{
Name: "scope-id",
EnvVar: "BOUNDARY_SCOPE_ID",
Target: &c.FlagScopeId,
Usage: "The scope ID to use for the operation.",
})
}

return set
}

Expand All @@ -81,20 +95,29 @@ func (c *LdapCommand) AutocompleteFlags() complete.Flags {
}

func (c *LdapCommand) Run(args []string) int {
f := c.Flags()
opts, err := common.GetOpts(c.Opts...)
if err != nil {
c.PrintCliError(err)
return base.CommandCliError
}
c.parsedOpts = opts

f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}

switch {
case c.flagLoginName == "":
c.PrintCliError(errors.New("Login name must be provided via -login-name"))
return base.CommandUserError
case c.FlagAuthMethodId == "":
c.PrintCliError(errors.New("Auth method ID must be provided via -auth-method-id"))
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 {
Expand Down Expand Up @@ -136,6 +159,23 @@ func (c *LdapCommand) Run(args []string) int {
}

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, ldap.AuthMethodPrefix)
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,
Expand Down
18 changes: 18 additions & 0 deletions internal/cmd/commands/authmethodscmd/ldap_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func init() {
}

type extraLdapCmdVars struct {
flagState string
flagUrls []string
flagInsecureTls bool
flagDiscoverDn bool
Expand Down Expand Up @@ -87,6 +88,7 @@ func extraLdapActionsFlagsMapFuncImpl() map[string][]string {
bindPasswordFlagName,
useTokenGroupsFlagName,
accountAttributeMaps,
stateFlagName,
},
}
flags["update"] = flags["create"]
Expand Down Expand Up @@ -212,6 +214,12 @@ func extraLdapFlagsFuncImpl(c *LdapCommand, set *base.FlagSets, _ *base.FlagSet)
Target: &c.flagUseTokenGroups,
Usage: "Use the Active Directory tokenGroups constructed attribute of the user to find the group memberships (optional).",
})
case stateFlagName:
f.StringVar(&base.StringVar{
Name: stateFlagName,
Target: &c.flagState,
Usage: "The desired operational state of the auth method.",
})
}
}
}
Expand Down Expand Up @@ -465,6 +473,16 @@ func extraLdapFlagHandlingFuncImpl(c *LdapCommand, _ *base.FlagSets, opts *[]aut
*opts = append(*opts, authmethods.WithLdapAuthMethodAccountAttributeMaps(c.flagAccountAttributeMaps))
}

switch c.flagState {
case "":
// there is a default value during "create", so it's okay to not
// specify a state
case "null":
c.UI.Error("State is required, you cannot set it to null")
return false
default:
*opts = append(*opts, authmethods.WithLdapAuthMethodState(c.flagState))
}
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,14 @@ message OidcAuthMethodAuthenticateTokenResponse {
message LdapAuthMethodAttributes {
// Output only. The state of the auth method. Will be "inactive",
// "active-private", or "active-public".
string state = 10 [json_name = "state"]; // @gotags: `class:"public"`
string state = 10 [
json_name = "state",
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.mask_mapping) = {
this: "attributes.state"
that: "OperationalState"
}
]; // @gotags: `class:"public"`

// start_tls if true, issues a StartTLS command after establishing an
// unencrypted connection. Defaults to false.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ message AuthMethod {
// operational_state is the current state of the auth_ldap_method (inactive,
// active-private, or active-public).
// @inject_tag: `gorm:"column:state;not_null"`
string operational_state = 80;
string operational_state = 80 [(custom_options.v1.mask_mapping) = {
this: "OperationalState"
that: "attributes.state"
}];

// start_tls if true, issues a StartTLS command after establishing an
// unencrypted connection. Defaults to false.
Expand Down
Loading