feat(authmethods): Add typed attributes to authenticate request and response
The AuthenticateRequest and AuthenticateResponse types have a complex mapping rule system, which requires a pair of custom callback functions.
This commit is contained in:
1 parent
0e51f9cc92
commit
a2bff4efdf
14 files changed
+1346
-678
No files matched your search
@@ -32,9 +32,16 @@ import (
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
subtypes.RegisterRequestTransformationFunc(&pbs.AuthenticateRequest{}, transformAuthenticateRequestAttributes)
|
||||
subtypes.RegisterResponseTransformationFunc(&pbs.AuthenticateResponse{}, transformAuthenticateResponseAttributes)
|
||||
}
|
||||
|
||||
const (
|
||||
// general auth method field names
|
||||
commandField = "command"
|
||||
@@ -792,7 +799,6 @@ func toAuthMethodProto(ctx context.Context, in auth.AuthMethod, opt ...handlers.
|
||||
OidcAuthMethodsAttributes: attrs,
|
||||
}
|
||||
}
|
||||
fmt.Println("attrs", out.Attrs)
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
@@ -1194,20 +1200,117 @@ func (s Service) convertToAuthenticateResponse(ctx context.Context, req *pbs.Aut
|
||||
ScopeId: authResults.Scope.Id,
|
||||
Type: resource.AuthToken,
|
||||
}
|
||||
tok.AuthorizedActions = authResults.FetchActionSetForId(ctx, tok.Id, authtokens.IdActions, requestauth.WithResource(res)).Strings()
|
||||
retAttrs, err := handlers.ProtoToStruct(tok)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenType := req.GetType()
|
||||
if tokenType == "" {
|
||||
// Fall back to deprecated field if type is not set
|
||||
tokenType = req.GetTokenType()
|
||||
}
|
||||
|
||||
tok.AuthorizedActions = authResults.FetchActionSetForId(ctx, tok.Id, authtokens.IdActions, requestauth.WithResource(res)).Strings()
|
||||
return &pbs.AuthenticateResponse{
|
||||
Command: req.GetCommand(),
|
||||
Attributes: retAttrs,
|
||||
Type: tokenType,
|
||||
Command: req.GetCommand(),
|
||||
Attrs: &pbs.AuthenticateResponse_AuthTokenResponse{
|
||||
AuthTokenResponse: tok,
|
||||
},
|
||||
Type: tokenType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func transformAuthenticateRequestAttributes(msg proto.Message) error {
|
||||
const op = "authmethod.transformAuthenticateRequestAttributes"
|
||||
authRequest, ok := msg.(*pbs.AuthenticateRequest)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s: message is not an AuthenticateRequest", op)
|
||||
}
|
||||
attrs := authRequest.GetAttributes()
|
||||
if attrs == nil {
|
||||
return nil
|
||||
}
|
||||
switch subtypes.SubtypeFromId(domain, authRequest.GetAuthMethodId()) {
|
||||
case password.Subtype:
|
||||
newAttrs := &pbs.PasswordLoginAttributes{}
|
||||
if err := handlers.StructToProto(attrs, newAttrs); err != nil {
|
||||
return err
|
||||
}
|
||||
authRequest.Attrs = &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: newAttrs,
|
||||
}
|
||||
case oidc.Subtype:
|
||||
switch authRequest.GetCommand() {
|
||||
case startCommand:
|
||||
newAttrs := &pbs.OidcStartAttributes{}
|
||||
if err := handlers.StructToProto(attrs, newAttrs); err != nil {
|
||||
return err
|
||||
}
|
||||
authRequest.Attrs = &pbs.AuthenticateRequest_OidcStartAttributes{
|
||||
OidcStartAttributes: newAttrs,
|
||||
}
|
||||
case callbackCommand:
|
||||
newAttrs := &pb.OidcAuthMethodAuthenticateCallbackRequest{}
|
||||
if err := handlers.StructToProto(attrs, newAttrs, handlers.WithDiscardUnknownFields(true)); err != nil {
|
||||
return err
|
||||
}
|
||||
authRequest.Attrs = &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: newAttrs,
|
||||
}
|
||||
case tokenCommand:
|
||||
newAttrs := &pb.OidcAuthMethodAuthenticateTokenRequest{}
|
||||
if err := handlers.StructToProto(attrs, newAttrs); err != nil {
|
||||
return err
|
||||
}
|
||||
authRequest.Attrs = &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: newAttrs,
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%s: unknown command %q", op, authRequest.GetCommand())
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%s: unknown auth method subtype in ID %q", op, authRequest.GetAuthMethodId())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformAuthenticateResponseAttributes(msg proto.Message) error {
|
||||
const op = "authmethod.transformAuthenticateResponseAttributes"
|
||||
authResponse, ok := msg.(*pbs.AuthenticateResponse)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s: message is not an AuthenticateResponse", op)
|
||||
}
|
||||
attrs := authResponse.GetAttrs()
|
||||
if attrs == nil {
|
||||
return nil
|
||||
}
|
||||
var newAttrs *structpb.Struct
|
||||
var err error
|
||||
switch attrs := attrs.(type) {
|
||||
case *pbs.AuthenticateResponse_Attributes:
|
||||
// No transformation necessary
|
||||
newAttrs = attrs.Attributes
|
||||
case *pbs.AuthenticateResponse_AuthTokenResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.AuthTokenResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateStartResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateStartResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateCallbackResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateTokenResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateTokenResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%s: unknown attributes type %T", op, attrs)
|
||||
}
|
||||
authResponse.Attrs = &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: newAttrs,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
package authmethods
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
|
||||
pba "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestTransformAuthenticateRequestAttributes(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := []struct {
|
||||
name string
|
||||
input *pbs.AuthenticateRequest
|
||||
expected *pbs.AuthenticateRequest
|
||||
}{
|
||||
{
|
||||
name: "empty-request",
|
||||
input: &pbs.AuthenticateRequest{},
|
||||
expected: &pbs.AuthenticateRequest{},
|
||||
},
|
||||
{
|
||||
name: "password-attributes",
|
||||
input: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "apw_test",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"login_name": structpb.NewStringValue("login-name"),
|
||||
"password": structpb.NewStringValue("password"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "apw_test",
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: "login-name",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-start-attributes",
|
||||
input: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "start",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"roundtrip_payload": structpb.NewStructValue(&structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
}),
|
||||
"cached_roundtrip_payload": structpb.NewStringValue("cached-roundtrip-payload"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "start",
|
||||
Attrs: &pbs.AuthenticateRequest_OidcStartAttributes{
|
||||
OidcStartAttributes: &pbs.OidcStartAttributes{
|
||||
RoundtripPayload: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
CachedRoundtripPayload: "cached-roundtrip-payload",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-callback-attributes",
|
||||
input: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "callback",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"code": structpb.NewStringValue("code"),
|
||||
"state": structpb.NewStringValue("state"),
|
||||
"error": structpb.NewStringValue("error"),
|
||||
"error_description": structpb.NewStringValue("error-description"),
|
||||
"error_uri": structpb.NewStringValue("error-uri"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "callback",
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: &pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Code: "code",
|
||||
State: "state",
|
||||
Error: "error",
|
||||
ErrorDescription: "error-description",
|
||||
ErrorUri: "error-uri",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-callback-attributes-with-extra-fields",
|
||||
input: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "callback",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"code": structpb.NewStringValue("code"),
|
||||
"state": structpb.NewStringValue("state"),
|
||||
"non-callback-field": structpb.NewBoolValue(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "callback",
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: &pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Code: "code",
|
||||
State: "state",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-token-attributes",
|
||||
input: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "token",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"token_id": structpb.NewStringValue("token-id"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "token",
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &pb.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: "token-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := proto.Clone(c.input)
|
||||
require.NoError(t, transformAuthenticateRequestAttributes(in))
|
||||
require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("not-an-authenticate-request", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pb.AuthMethod{}))
|
||||
})
|
||||
t.Run("invalid-auth-method-id", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
AuthMethodId: "invalid",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{},
|
||||
},
|
||||
}))
|
||||
})
|
||||
t.Run("invalid-oidc-command", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "invalid",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{},
|
||||
},
|
||||
}))
|
||||
})
|
||||
t.Run("invalid-password-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
AuthMethodId: "apw_test",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
t.Run("invalid-oidc-start-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "start",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
t.Run("invalid-oidc-token-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "token",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTransformAuthenticateResponseAttributes(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := []struct {
|
||||
name string
|
||||
input *pbs.AuthenticateResponse
|
||||
expected *pbs.AuthenticateResponse
|
||||
}{
|
||||
{
|
||||
name: "empty-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unstructured-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"field1": structpb.NewBoolValue(true),
|
||||
"field2": structpb.NewStringValue("value2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "authtoken-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_AuthTokenResponse{
|
||||
AuthTokenResponse: &pba.AuthToken{
|
||||
Id: "token-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"id": structpb.NewStringValue("token-id"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-start-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateStartResponse{
|
||||
OidcAuthMethodAuthenticateStartResponse: &pb.OidcAuthMethodAuthenticateStartResponse{
|
||||
AuthUrl: "auth-url",
|
||||
TokenId: "token-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"auth_url": structpb.NewStringValue("auth-url"),
|
||||
"token_id": structpb.NewStringValue("token-id"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-callback-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse{
|
||||
OidcAuthMethodAuthenticateCallbackResponse: &pb.OidcAuthMethodAuthenticateCallbackResponse{
|
||||
FinalRedirectUrl: "final-redirect-url",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"final_redirect_url": structpb.NewStringValue("final-redirect-url"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "oidc-token-attributes",
|
||||
input: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateTokenResponse{
|
||||
OidcAuthMethodAuthenticateTokenResponse: &pb.OidcAuthMethodAuthenticateTokenResponse{
|
||||
Status: "status",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &pbs.AuthenticateResponse{
|
||||
Command: "testcommand",
|
||||
Attrs: &pbs.AuthenticateResponse_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"status": structpb.NewStringValue("status"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := proto.Clone(c.input)
|
||||
require.NoError(t, transformAuthenticateResponseAttributes(in))
|
||||
require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformAuthenticateResponseAttributesErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("not-an-authenticate-response", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateResponseAttributes(&pb.AuthMethod{}))
|
||||
})
|
||||
}
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -159,7 +158,7 @@ func (s Service) authenticateOidc(ctx context.Context, req *pbs.AuthenticateRequ
|
||||
return s.authenticateOidcToken(ctx, req, authResults)
|
||||
}
|
||||
|
||||
return &pbs.AuthenticateResponse{Command: req.GetCommand(), Attributes: nil}, nil
|
||||
return &pbs.AuthenticateResponse{Command: req.GetCommand()}, nil
|
||||
}
|
||||
|
||||
func (s Service) authenticateOidcStart(ctx context.Context, req *pbs.AuthenticateRequest) (*pbs.AuthenticateResponse, error) {
|
||||
@@ -169,10 +168,7 @@ func (s Service) authenticateOidcStart(ctx context.Context, req *pbs.Authenticat
|
||||
}
|
||||
|
||||
var opts []oidc.Option
|
||||
attrs := new(pbs.OidcStartAttributes)
|
||||
if err := handlers.StructToProto(req.GetAttributes(), attrs); err != nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "Error parsing request attributes.", errors.WithWrap(err))
|
||||
}
|
||||
attrs := req.GetOidcStartAttributes()
|
||||
if attrs.GetCachedRoundtripPayload() != "" {
|
||||
opts = append(opts, oidc.WithRoundtripPayload(attrs.GetCachedRoundtripPayload()))
|
||||
}
|
||||
@@ -185,15 +181,15 @@ func (s Service) authenticateOidcStart(ctx context.Context, req *pbs.Authenticat
|
||||
return nil, errors.New(ctx, errors.Internal, op, "Error generating parameters for starting the OIDC flow. See the controller's log for more information.")
|
||||
}
|
||||
|
||||
respAttrs := &pb.OidcAuthMethodAuthenticateStartResponse{
|
||||
AuthUrl: authUrl.String(),
|
||||
TokenId: tokenId,
|
||||
}
|
||||
resp := &pbs.AuthenticateResponse{Command: req.GetCommand()}
|
||||
if resp.Attributes, err = handlers.ProtoToStruct(respAttrs); err != nil {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "Error marshaling parameters.", errors.WithWrap(err))
|
||||
}
|
||||
return resp, nil
|
||||
return &pbs.AuthenticateResponse{
|
||||
Command: req.GetCommand(),
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateStartResponse{
|
||||
OidcAuthMethodAuthenticateStartResponse: &pb.OidcAuthMethodAuthenticateStartResponse{
|
||||
AuthUrl: authUrl.String(),
|
||||
TokenId: tokenId,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// authenticateOidcCallback behaves differently than other service methods.
|
||||
@@ -236,20 +232,17 @@ func (s Service) authenticateOidcCallback(ctx context.Context, req *pbs.Authenti
|
||||
}
|
||||
u.Add("error", string(out))
|
||||
errRedirect := fmt.Sprintf("%s?%s", errRedirectBase, u.Encode())
|
||||
respAttrs, err := handlers.ProtoToStruct(&pb.OidcAuthMethodAuthenticateCallbackResponse{
|
||||
FinalRedirectUrl: errRedirect,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("failed creating error redirect response"))
|
||||
}
|
||||
return &pbs.AuthenticateResponse{Command: callbackCommand, Attributes: respAttrs}, nil
|
||||
return &pbs.AuthenticateResponse{
|
||||
Command: callbackCommand,
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse{
|
||||
OidcAuthMethodAuthenticateCallbackResponse: &pb.OidcAuthMethodAuthenticateCallbackResponse{
|
||||
FinalRedirectUrl: errRedirect,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
attrs := new(pb.OidcAuthMethodAuthenticateCallbackRequest)
|
||||
// Note that this conversion has already happened in the validate call so we don't expect errors here.
|
||||
if err := handlers.StructToProto(req.GetAttributes(), attrs, handlers.WithDiscardUnknownFields(true)); err != nil {
|
||||
return errResponse(err)
|
||||
}
|
||||
attrs := req.GetOidcAuthMethodAuthenticateCallbackRequest()
|
||||
|
||||
var finalRedirectUrl string
|
||||
if attrs.GetError() != "" {
|
||||
@@ -268,14 +261,14 @@ func (s Service) authenticateOidcCallback(ctx context.Context, req *pbs.Authenti
|
||||
return errResponse(errors.New(ctx, errors.InvalidParameter, op, "Callback validation failed.", errors.WithWrap(err)))
|
||||
}
|
||||
|
||||
respAttrs, err := handlers.ProtoToStruct(&pb.OidcAuthMethodAuthenticateCallbackResponse{
|
||||
FinalRedirectUrl: finalRedirectUrl,
|
||||
})
|
||||
if err != nil {
|
||||
return errResponse(errors.New(ctx, errors.Internal, op, "Error marshaling parameters after successful callback", errors.WithWrap(err)))
|
||||
}
|
||||
|
||||
return &pbs.AuthenticateResponse{Command: req.GetCommand(), Attributes: respAttrs}, nil
|
||||
return &pbs.AuthenticateResponse{
|
||||
Command: req.GetCommand(),
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse{
|
||||
OidcAuthMethodAuthenticateCallbackResponse: &pb.OidcAuthMethodAuthenticateCallbackResponse{
|
||||
FinalRedirectUrl: finalRedirectUrl,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s Service) authenticateOidcToken(ctx context.Context, req *pbs.AuthenticateRequest, authResults *auth.VerifyResults) (*pbs.AuthenticateResponse, error) {
|
||||
@@ -286,14 +279,11 @@ func (s Service) authenticateOidcToken(ctx context.Context, req *pbs.Authenticat
|
||||
if authResults == nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "Nil auth results.")
|
||||
}
|
||||
if req.GetAttributes() == nil {
|
||||
if req.GetOidcAuthMethodAuthenticateTokenRequest() == nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "Nil request attributes.")
|
||||
}
|
||||
|
||||
attrs := new(pb.OidcAuthMethodAuthenticateTokenRequest)
|
||||
if err := handlers.StructToProto(req.GetAttributes(), attrs); err != nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "Error parsing request attributes.", errors.WithWrap(err))
|
||||
}
|
||||
attrs := req.GetOidcAuthMethodAuthenticateTokenRequest()
|
||||
if attrs.TokenId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "Empty token ID in request attributes.")
|
||||
}
|
||||
@@ -313,15 +303,16 @@ func (s Service) authenticateOidcToken(ctx context.Context, req *pbs.Authenticat
|
||||
}
|
||||
}
|
||||
if token == nil {
|
||||
attrs, err := structpb.NewStruct(map[string]interface{}{
|
||||
statusField: "unknown",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "Error generating response attributes.", errors.WithWrap(err))
|
||||
}
|
||||
return &pbs.AuthenticateResponse{
|
||||
Command: req.Command,
|
||||
Attributes: attrs,
|
||||
Command: req.Command,
|
||||
Attrs: &pbs.AuthenticateResponse_OidcAuthMethodAuthenticateTokenResponse{
|
||||
OidcAuthMethodAuthenticateTokenResponse: &pb.OidcAuthMethodAuthenticateTokenResponse{
|
||||
Status: "unknown",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -340,12 +331,8 @@ func validateAuthenticateOidcRequest(req *pbs.AuthenticateRequest) error {
|
||||
|
||||
switch req.GetCommand() {
|
||||
case startCommand:
|
||||
if req.GetAttributes() != nil {
|
||||
attrs := new(pbs.OidcStartAttributes)
|
||||
if err := handlers.StructToProto(req.GetAttributes(), attrs); err != nil {
|
||||
badFields[attributesField] = "Could not be parsed, or contains invalid fields."
|
||||
break
|
||||
}
|
||||
if req.GetOidcStartAttributes() != nil {
|
||||
attrs := req.GetOidcStartAttributes()
|
||||
|
||||
// Ensure we pay no attention to cache information provided by the client
|
||||
attrs.CachedRoundtripPayload = ""
|
||||
@@ -362,23 +349,10 @@ func validateAuthenticateOidcRequest(req *pbs.AuthenticateRequest) error {
|
||||
} else {
|
||||
// Cache for later
|
||||
attrs.CachedRoundtripPayload = string(m)
|
||||
req.Attributes, err = handlers.ProtoToStruct(attrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert map back to proto")
|
||||
}
|
||||
}
|
||||
}
|
||||
case callbackCommand:
|
||||
if req.GetAttributes() == nil {
|
||||
badFields[attributesField] = "No callback attributes provided."
|
||||
break
|
||||
}
|
||||
|
||||
attrs := new(pb.OidcAuthMethodAuthenticateCallbackRequest)
|
||||
if err := handlers.StructToProto(req.GetAttributes(), attrs, handlers.WithDiscardUnknownFields(true)); err != nil {
|
||||
badFields[attributesField] = "Unable to parse callback request attributes."
|
||||
break
|
||||
}
|
||||
attrs := req.GetOidcAuthMethodAuthenticateCallbackRequest()
|
||||
|
||||
if attrs.GetCode() == "" && attrs.GetError() == "" {
|
||||
badFields[codeField] = "Code field not supplied in callback request."
|
||||
|
||||
@@ -1404,12 +1404,13 @@ func TestChangeState_OIDC(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Make Complete Private",
|
||||
req: &pbs.ChangeStateRequest{Id: oidcam.GetPublicId(), Version: oidcam.GetVersion(), Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "active-private",
|
||||
req: &pbs.ChangeStateRequest{
|
||||
Id: oidcam.GetPublicId(), Version: oidcam.GetVersion(), Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "active-private",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: &pbs.ChangeStateResponse{Item: func() *pb.AuthMethod {
|
||||
am := proto.Clone(wantTemplate).(*pb.AuthMethod)
|
||||
am.GetOidcAuthMethodsAttributes().State = "active-private"
|
||||
@@ -1419,12 +1420,13 @@ func TestChangeState_OIDC(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Make Complete Public",
|
||||
req: &pbs.ChangeStateRequest{Id: oidcam.GetPublicId(), Version: 2, Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "active-public",
|
||||
req: &pbs.ChangeStateRequest{
|
||||
Id: oidcam.GetPublicId(), Version: 2, Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "active-public",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: &pbs.ChangeStateResponse{Item: func() *pb.AuthMethod {
|
||||
am := proto.Clone(wantTemplate).(*pb.AuthMethod)
|
||||
am.GetOidcAuthMethodsAttributes().State = "active-public"
|
||||
@@ -1434,12 +1436,13 @@ func TestChangeState_OIDC(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Make Complete Inactive",
|
||||
req: &pbs.ChangeStateRequest{Id: oidcam.GetPublicId(), Version: 3, Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "inactive",
|
||||
req: &pbs.ChangeStateRequest{
|
||||
Id: oidcam.GetPublicId(), Version: 3, Attrs: &pbs.ChangeStateRequest_OidcChangeStateAttributes{
|
||||
OidcChangeStateAttributes: &pbs.OidcChangeStateAttributes{
|
||||
State: "inactive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: &pbs.ChangeStateResponse{Item: func() *pb.AuthMethod {
|
||||
am := proto.Clone(wantTemplate).(*pb.AuthMethod)
|
||||
am.GetOidcAuthMethodsAttributes().State = "inactive"
|
||||
@@ -1529,16 +1532,18 @@ func TestAuthenticate_OIDC_Start(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Command: "start",
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
ret, err := structpb.NewStruct(map[string]interface{}{
|
||||
"roundtrip_payload": map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"baz": true,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_OidcStartAttributes{
|
||||
OidcStartAttributes: &pbs.OidcStartAttributes{
|
||||
RoundtripPayload: func() *structpb.Struct {
|
||||
ret, err := structpb.NewStruct(map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"baz": true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1556,13 +1561,10 @@ func TestAuthenticate_OIDC_Start(t *testing.T) {
|
||||
require.Equal(got.GetCommand(), "start")
|
||||
// We can't really compare directly as a lot of the values contain
|
||||
// random data, so just verify existence
|
||||
require.NotNil(got.GetAttributes())
|
||||
m := got.GetAttributes().AsMap()
|
||||
require.NotNil(m)
|
||||
require.Contains(m, "auth_url")
|
||||
require.NotEmpty(m["auth_url"])
|
||||
require.Contains(m, "token_id")
|
||||
require.NotEmpty(m["token_id"])
|
||||
got.GetAuthTokenResponse()
|
||||
require.NotNil(got.GetOidcAuthMethodAuthenticateStartResponse())
|
||||
require.NotEmpty(got.GetOidcAuthMethodAuthenticateStartResponse().GetAuthUrl())
|
||||
require.NotEmpty(got.GetOidcAuthMethodAuthenticateStartResponse().GetTokenId())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1623,18 +1625,16 @@ func TestAuthenticate_OIDC_Token(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Command: "token",
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
ret, err := structpb.NewStruct(map[string]interface{}{
|
||||
"token_id": func() string {
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &pb.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: func() string {
|
||||
tokenPublicId, err := authtoken.NewAuthTokenId()
|
||||
require.NoError(t, err)
|
||||
oidc.TestPendingToken(t, testAtRepo, testUser, testAcct, tokenPublicId)
|
||||
return oidc.TestTokenRequestId(t, s.authMethod, s.kmsCache, 200*time.Second, tokenPublicId)
|
||||
}(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1642,18 +1642,16 @@ func TestAuthenticate_OIDC_Token(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Command: "token",
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
ret, err := structpb.NewStruct(map[string]interface{}{
|
||||
"token_id": func() string {
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &pb.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: func() string {
|
||||
tokenPublicId, err := authtoken.NewAuthTokenId()
|
||||
require.NoError(t, err)
|
||||
oidc.TestPendingToken(t, testAtRepo, testUser, testAcct, tokenPublicId)
|
||||
return oidc.TestTokenRequestId(t, s.authMethod, s.kmsCache, -20*time.Second, tokenPublicId)
|
||||
}(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrMatch: errors.T(errors.AuthAttemptExpired),
|
||||
},
|
||||
@@ -1662,13 +1660,11 @@ func TestAuthenticate_OIDC_Token(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Command: "token",
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
ret, err := structpb.NewStruct(map[string]interface{}{
|
||||
"token_id": "bad-token-id",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return ret
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &pb.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: "bad-token-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrMatch: errors.T(errors.Unknown),
|
||||
},
|
||||
@@ -1689,11 +1685,8 @@ func TestAuthenticate_OIDC_Token(t *testing.T) {
|
||||
}
|
||||
require.NoError(err)
|
||||
require.Equal(got.GetCommand(), "token")
|
||||
require.NotNil(got.GetAttributes())
|
||||
m := got.GetAttributes().AsMap()
|
||||
require.NotNil(m)
|
||||
require.Contains(m, "token")
|
||||
require.NotEmpty(m["token"])
|
||||
require.NotNil(got.GetAuthTokenResponse())
|
||||
require.NotEmpty(got.GetAuthTokenResponse().GetToken())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1710,27 +1703,23 @@ func TestAuthenticate_OIDC_Callback_ErrorRedirect(t *testing.T) {
|
||||
req: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Command: "callback",
|
||||
Attributes: func() *structpb.Struct {
|
||||
st, err := handlers.ProtoToStruct(&pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: &pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
State: "anything",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No Auth Method Id",
|
||||
req: &pbs.AuthenticateRequest{
|
||||
Command: "callback",
|
||||
Attributes: func() *structpb.Struct {
|
||||
st, err := handlers.ProtoToStruct(&pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: &pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Code: "anythingworks",
|
||||
State: "anything",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1738,13 +1727,11 @@ func TestAuthenticate_OIDC_Callback_ErrorRedirect(t *testing.T) {
|
||||
req: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Command: "callback",
|
||||
Attributes: func() *structpb.Struct {
|
||||
st, err := handlers.ProtoToStruct(&pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: &pb.OidcAuthMethodAuthenticateCallbackRequest{
|
||||
Code: "anythingworks",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1784,16 +1771,13 @@ func TestAuthenticate_OIDC_Callback_ErrorRedirect(t *testing.T) {
|
||||
&pbs.AuthenticateRequest{
|
||||
AuthMethodId: s.authMethod.GetPublicId(),
|
||||
Command: "callback",
|
||||
Attributes: func() *structpb.Struct {
|
||||
st, err := handlers.ProtoToStruct(tc.attrs)
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest{
|
||||
OidcAuthMethodAuthenticateCallbackRequest: tc.attrs,
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
respAttrs := &pb.OidcAuthMethodAuthenticateCallbackResponse{}
|
||||
require.NoError(t, handlers.StructToProto(got.GetAttributes(), respAttrs))
|
||||
respAttrs := got.GetOidcAuthMethodAuthenticateCallbackResponse()
|
||||
assert.Contains(t, respAttrs.FinalRedirectUrl, fmt.Sprintf("%s/authentication-error?", s.authMethod.GetApiUrl()))
|
||||
u, err := url.Parse(respAttrs.GetFinalRedirectUrl())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -88,8 +88,8 @@ func (s Service) updatePwInRepo(ctx context.Context, scopeId, id string, mask []
|
||||
}
|
||||
|
||||
func (s Service) authenticatePassword(ctx context.Context, req *pbs.AuthenticateRequest, authResults *auth.VerifyResults) (*pbs.AuthenticateResponse, error) {
|
||||
reqAttrs := req.GetAttributes().GetFields()
|
||||
tok, err := s.authenticateWithPwRepo(ctx, authResults.Scope.GetId(), req.GetAuthMethodId(), reqAttrs[loginNameField].GetStringValue(), reqAttrs[passwordField].GetStringValue())
|
||||
reqAttrs := req.GetPasswordLoginAttributes()
|
||||
tok, err := s.authenticateWithPwRepo(ctx, authResults.Scope.GetId(), req.GetAuthMethodId(), reqAttrs.LoginName, reqAttrs.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -136,17 +136,11 @@ func (s Service) authenticateWithPwRepo(ctx context.Context, scopeId, authMethod
|
||||
func validateAuthenticatePasswordRequest(req *pbs.AuthenticateRequest) error {
|
||||
badFields := make(map[string]string)
|
||||
|
||||
if req.GetAttributes() == nil || req.GetAttributes().GetFields() == nil {
|
||||
badFields["attributes"] = "This is a required field."
|
||||
// Return early because we need non-nil values in the rest of the check.
|
||||
return handlers.InvalidArgumentErrorf("Invalid fields provided in request.", badFields)
|
||||
}
|
||||
|
||||
attrs := req.GetAttributes().GetFields()
|
||||
if _, ok := attrs[loginNameField]; !ok {
|
||||
attrs := req.GetPasswordLoginAttributes()
|
||||
if attrs.LoginName == "" {
|
||||
badFields["attributes.login_name"] = "This is a required field."
|
||||
}
|
||||
if _, ok := attrs[passwordField]; !ok {
|
||||
if attrs.Password == "" {
|
||||
badFields["attributes.password"] = "This is a required field."
|
||||
}
|
||||
if req.GetCommand() == "" {
|
||||
|
||||
@@ -19,14 +19,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authmethods"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
|
||||
authtokenpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
|
||||
scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/genproto/protobuf/field_mask"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
@@ -510,13 +508,12 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantType: "token",
|
||||
},
|
||||
@@ -525,13 +522,12 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "cookie",
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantType: "cookie",
|
||||
},
|
||||
@@ -539,13 +535,12 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
name: "no-token-type",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -553,26 +548,24 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "email",
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "no-authmethod",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
@@ -581,13 +574,12 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "wrong"}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: "wrong",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.Unauthenticated),
|
||||
},
|
||||
@@ -596,13 +588,12 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: "wrong"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: "wrong",
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: handlers.ApiErrorWithCode(codes.Unauthenticated),
|
||||
},
|
||||
@@ -621,8 +612,8 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
aToken := &authtokenpb.AuthToken{}
|
||||
require.NoError(handlers.StructToProto(resp.GetAttributes(), aToken, handlers.WithDiscardUnknownFields(true)))
|
||||
|
||||
aToken := resp.GetAuthTokenResponse()
|
||||
assert.NotEmpty(aToken.GetId())
|
||||
assert.NotEmpty(aToken.GetToken())
|
||||
assert.True(strings.HasPrefix(aToken.GetToken(), aToken.GetId()))
|
||||
@@ -678,18 +669,16 @@ func TestAuthenticate_AuthAccountConnectedToIamUser_Password(t *testing.T) {
|
||||
require.NoError(err)
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
Attributes: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"login_name": {Kind: &structpb.Value_StringValue{StringValue: testLoginName}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
|
||||
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
|
||||
LoginName: testLoginName,
|
||||
Password: testPassword,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
aToken := &authtokenpb.AuthToken{}
|
||||
require.NoError(handlers.StructToProto(resp.GetAttributes(), aToken, handlers.WithDiscardUnknownFields(true)))
|
||||
aToken := resp.GetAuthTokenResponse()
|
||||
assert.Equal(iamUser.GetPublicId(), aToken.GetUserId())
|
||||
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
|
||||
assert.Equal(acct.GetPublicId(), aToken.GetAccountId())
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
|
||||
pba "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/metadata"
|
||||
@@ -19,9 +19,9 @@ import (
|
||||
|
||||
func TestOutgoingSplitCookie(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
attrs, err := ProtoToStruct(&pb.AuthToken{Token: "t_abc_1234567890"})
|
||||
attrs, err := ProtoToStruct(&pba.AuthToken{Token: "t_abc_1234567890"})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, OutgoingResponseFilter(context.Background(), rec, &pbs.AuthenticateResponse{Attributes: attrs, Type: "cookie"}))
|
||||
require.NoError(t, OutgoingResponseFilter(context.Background(), rec, &pbs.AuthenticateResponse{Attrs: &pbs.AuthenticateResponse_Attributes{Attributes: attrs}, Type: "cookie"}))
|
||||
assert.ElementsMatch(t, rec.Result().Cookies(), []*http.Cookie{
|
||||
{Name: HttpOnlyCookieName, Value: "34567890", HttpOnly: true, Raw: "wt-http-token-cookie=34567890; HttpOnly"},
|
||||
{Name: JsVisibleCookieName, Value: "t_abc_12", Raw: "wt-js-token-cookie=t_abc_12"},
|
||||
|
||||
Reference in new issue
Block a user