Skip to content

Commit

Permalink
feature (cli/ldap/authenticate): use primary auth method if none is p…
Browse files Browse the repository at this point in the history
…rovided (#2890)

* fix (auth/ldap): support setting the state attribute

* feature (cli/ldap/authenticate): use primary auth method if none is provided
  • Loading branch information
jimlambrt committed Feb 6, 2023
1 parent 89acc5b commit f1433d5
Show file tree
Hide file tree
Showing 8 changed files with 536 additions and 434 deletions.
24 changes: 24 additions & 0 deletions api/authmethods/option.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,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.

7 changes: 6 additions & 1 deletion internal/cmd/commands/authenticate/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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 @@ -112,8 +113,12 @@ 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))
c.PrintCliError(fmt.Errorf("The primary auth method was of an unsupported type. The given ID was %s; only 'ampw' (password), 'amoidc' (OIDC) and 'amldap' (LDAP) 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 @@ -313,7 +313,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

0 comments on commit f1433d5

Please sign in to comment.