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
File diff suppressed because it is too large.
Load diff
@@ -42,9 +42,6 @@ message AuthToken {
|
||||
// Output only. The time this Auth Token expires.
|
||||
google.protobuf.Timestamp expiration_time = 110 [json_name="expiration_time"];
|
||||
|
||||
// Output only. The type of this auth token. Either "cookie" or "token".
|
||||
string token_type = 120 [json_name="token_type"];
|
||||
|
||||
// Output only. The available actions on this resource for this user.
|
||||
repeated string authorized_actions = 300 [json_name="authorized_actions"];
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import "google/api/visibility.proto";
|
||||
import "google/protobuf/field_mask.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
import "controller/api/resources/authmethods/v1/auth_method.proto";
|
||||
import "controller/api/resources/authtokens/v1/authtoken.proto";
|
||||
import "controller/custom_options/v1/options.proto";
|
||||
|
||||
option (custom_options.v1.domain) = "auth";
|
||||
@@ -196,15 +197,6 @@ message OidcStartAttributes {
|
||||
string cached_roundtrip_payload = 2;
|
||||
}
|
||||
|
||||
// The layout of the struct for "attributes" field in AuthenticateRequest for a
|
||||
// oidc type's token command. This message isn't directly referenced anywhere
|
||||
// but is used here to define the expected field names and types.
|
||||
message OidcTokenAttributes {
|
||||
// The token id for the request. This is the token id that was returned from
|
||||
// the oidc type's start command
|
||||
string token_id = 1;
|
||||
}
|
||||
|
||||
message AuthenticateRequest {
|
||||
// The ID of the Auth Method in the system that should be used for authentication.
|
||||
string auth_method_id = 1 [json_name = "auth_method_id"]; // @gotags: `class:"public"`
|
||||
@@ -214,8 +206,16 @@ message AuthenticateRequest {
|
||||
// This can be "cookie" or "token". If not provided, "token" will be used. "cookie" activates a split-cookie method where the token is split partially between http-only and regular cookies in order
|
||||
// to keep it safe from rogue JS in the browser.
|
||||
string type = 6 [json_name = "type"]; // @gotags: `class:"public"`
|
||||
// Attributes are passed to the Auth Method; the valid keys and values depend on the type of Auth Method as well as the command.
|
||||
google.protobuf.Struct attributes = 4 [json_name = "attributes"];
|
||||
oneof attrs {
|
||||
// Attributes are passed to the Auth Method; the valid keys and values depend on the type of Auth Method as well as the command.
|
||||
google.protobuf.Struct attributes = 4;
|
||||
// Note: these fields have a custom mapping function for transforming to and from the generic attributes,
|
||||
// they do not use the standard attribute transformation.
|
||||
PasswordLoginAttributes password_login_attributes = 7 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
OidcStartAttributes oidc_start_attributes = 8 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
controller.api.resources.authmethods.v1.OidcAuthMethodAuthenticateCallbackRequest oidc_auth_method_authenticate_callback_request = 9 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
controller.api.resources.authmethods.v1.OidcAuthMethodAuthenticateTokenRequest oidc_auth_method_authenticate_token_request = 10 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
}
|
||||
// The command to perform.
|
||||
string command = 5 [json_name = "command"]; // @gotags: `class:"public"`
|
||||
|
||||
@@ -229,8 +229,16 @@ message AuthenticateResponse {
|
||||
reserved "item", "token_type";
|
||||
// The type of the token returned. Either "cookie" or "token".
|
||||
string type = 3; // @gotags: `class:"public"`
|
||||
// Valid keys and values depend on the type of Auth Method as well as the command.
|
||||
google.protobuf.Struct attributes = 4 [json_name = "attributes"];
|
||||
oneof attrs {
|
||||
// Valid keys and values depend on the type of Auth Method as well as the command.
|
||||
google.protobuf.Struct attributes = 4 [json_name = "attributes"];
|
||||
// Note: these fields have a custom mapping function for transforming to and from the generic attributes,
|
||||
// they do not use the standard attribute transformation.
|
||||
controller.api.resources.authmethods.v1.OidcAuthMethodAuthenticateStartResponse oidc_auth_method_authenticate_start_response = 6 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
controller.api.resources.authmethods.v1.OidcAuthMethodAuthenticateCallbackResponse oidc_auth_method_authenticate_callback_response = 7 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
controller.api.resources.authmethods.v1.OidcAuthMethodAuthenticateTokenResponse oidc_auth_method_authenticate_token_response = 8 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
controller.api.resources.authtokens.v1.AuthToken auth_token_response = 9 [(google.api.field_visibility).restriction = "INTERNAL"];
|
||||
}
|
||||
// The command that was performed.
|
||||
string command = 5 [json_name = "command"]; // @gotags: `class:"public"`
|
||||
}
|
||||
@@ -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"},
|
||||
|
||||
@@ -84,11 +84,13 @@ func TestAuthenticate(t *testing.T) {
|
||||
// TODO(johanbrandhorst): revert this when classification is done for auth methods
|
||||
reqDetails := tests_api.GetEventDetails(t, got, "request")
|
||||
tests_api.AssertRedactedValues(t, reqDetails)
|
||||
tests_api.AssertRedactedValues(t, reqDetails["attributes"], "password", "login_name")
|
||||
tests_api.AssertRedactedValues(t, reqDetails["Attrs"])
|
||||
tests_api.AssertRedactedValues(t, reqDetails["Attrs"].(map[string]interface{})["PasswordLoginAttributes"], "password", "login_name")
|
||||
|
||||
respDetails := tests_api.GetEventDetails(t, got, "response")
|
||||
tests_api.AssertRedactedValues(t, respDetails)
|
||||
tests_api.AssertRedactedValues(t, respDetails["attributes"], "token", "approximate_last_used_time", "expiration_time", "token_type", "updated_time", "user_id", "account_id", "auth_method_id", "authorized_actions", "created_time", "id")
|
||||
tests_api.AssertRedactedValues(t, respDetails["Attrs"])
|
||||
tests_api.AssertRedactedValues(t, respDetails["Attrs"].(map[string]interface{})["AuthTokenResponse"], "token", "token_type", "user_id", "account_id", "auth_method_id", "authorized_actions", "id", "scope_id")
|
||||
|
||||
_ = os.WriteFile(eventConfig.AuditEvents.Name(), nil, 0o666) // clean out audit events from previous calls
|
||||
tok, err = methods.Authenticate(tc.Context(), tc.Server().DevPasswordAuthMethodId, "login", map[string]interface{}{"login_name": "user", "password": "bad-pass"})
|
||||
@@ -98,5 +100,6 @@ func TestAuthenticate(t *testing.T) {
|
||||
|
||||
reqDetails = tests_api.GetEventDetails(t, got, "request")
|
||||
tests_api.AssertRedactedValues(t, reqDetails)
|
||||
tests_api.AssertRedactedValues(t, reqDetails["attributes"], "password", "login_name")
|
||||
tests_api.AssertRedactedValues(t, reqDetails["Attrs"])
|
||||
tests_api.AssertRedactedValues(t, reqDetails["Attrs"].(map[string]interface{})["PasswordLoginAttributes"], "password", "login_name")
|
||||
}
|
||||
@@ -187,9 +187,16 @@ func TestList(t *testing.T) {
|
||||
result, err = amClient.List(tc.Context(), global)
|
||||
require.NoError(err)
|
||||
require.Len(result.Items, 3)
|
||||
assert.Empty(cmp.Diff(genOIDCAM, result.Items[0], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(genPWAM, result.Items[1], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(pwAM.Item, result.Items[2], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(
|
||||
cmp.Diff(
|
||||
result.Items,
|
||||
[]*authmethods.AuthMethod{genOIDCAM, genPWAM, pwAM.Item},
|
||||
cmpopts.IgnoreUnexported(authmethods.AuthMethod{}),
|
||||
cmpopts.SortSlices(func(a, b *authmethods.AuthMethod) bool {
|
||||
return a.Name < b.Name
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
oidcAM, err := amClient.Create(tc.Context(), "oidc", global,
|
||||
authmethods.WithName("foo"),
|
||||
@@ -206,10 +213,16 @@ func TestList(t *testing.T) {
|
||||
result, err = amClient.List(tc.Context(), global)
|
||||
require.NoError(err)
|
||||
require.Len(result.Items, 4)
|
||||
assert.Empty(cmp.Diff(genOIDCAM, result.Items[0], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(oidcAM.Item, result.Items[1], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(genPWAM, result.Items[2], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(pwAM.Item, result.Items[3], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(
|
||||
cmp.Diff(
|
||||
result.Items,
|
||||
[]*authmethods.AuthMethod{genOIDCAM, genPWAM, pwAM.Item, oidcAM.Item},
|
||||
cmpopts.IgnoreUnexported(authmethods.AuthMethod{}),
|
||||
cmpopts.SortSlices(func(a, b *authmethods.AuthMethod) bool {
|
||||
return a.Name < b.Name
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
result, err = amClient.List(tc.Context(), global,
|
||||
authmethods.WithFilter(`"/item/attributes/client_id"=="client-id"`))
|
||||
@@ -221,8 +234,16 @@ func TestList(t *testing.T) {
|
||||
authmethods.WithFilter(`"/item/attributes/min_login_name_length"==3`))
|
||||
require.NoError(err)
|
||||
require.Len(result.Items, 2)
|
||||
assert.Empty(cmp.Diff(genPWAM, result.Items[0], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(cmp.Diff(pwAM.Item, result.Items[1], cmpopts.IgnoreUnexported(authmethods.AuthMethod{})))
|
||||
assert.Empty(
|
||||
cmp.Diff(
|
||||
result.Items,
|
||||
[]*authmethods.AuthMethod{genPWAM, pwAM.Item},
|
||||
cmpopts.IgnoreUnexported(authmethods.AuthMethod{}),
|
||||
cmpopts.SortSlices(func(a, b *authmethods.AuthMethod) bool {
|
||||
return a.Name < b.Name
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
result, err = amClient.List(tc.Context(), global,
|
||||
authmethods.WithFilter(`"/item/attributes/min_password_length"==10`))
|
||||
|
||||
@@ -8,12 +8,15 @@ import (
|
||||
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
"github.com/hashicorp/boundary/sdk/wrapper"
|
||||
"github.com/hashicorp/eventlogger"
|
||||
"github.com/hashicorp/eventlogger/filters/encrypt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// TestAuthenticate_Tags will test that the response filtering aligns with the
|
||||
@@ -38,26 +41,31 @@ func TestAuthenticate_Tags(t *testing.T) {
|
||||
CreatedAt: now,
|
||||
Payload: &services.AuthenticateResponse{
|
||||
Command: "public-command",
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"account_id": structpb.NewStringValue("public-account_id"),
|
||||
"approximate_last_used_time": structpb.NewStringValue("public-approximate_last_used_time"),
|
||||
"auth_method_id": structpb.NewStringValue("public-auth_method_id"),
|
||||
"authorized_actions": structpb.NewStringValue("public-authorized_actions"),
|
||||
"created_time": structpb.NewStringValue("public-created_time"),
|
||||
"expiration_time": structpb.NewStringValue("public-expiration_time"),
|
||||
"id": structpb.NewStringValue("public-id"),
|
||||
"scope": structpb.NewStringValue("public-scope"),
|
||||
"type": structpb.NewStringValue("public-type"),
|
||||
"updated_time": structpb.NewStringValue("public-updated_time"),
|
||||
"user_id": structpb.NewStringValue("public-user_id"),
|
||||
"status": structpb.NewStringValue("public-status"),
|
||||
"auth_url": structpb.NewStringValue("public-auth_url"),
|
||||
"token_id": structpb.NewStringValue("public-token_id"),
|
||||
"final_redirect_url": structpb.NewStringValue("public-final_redirect_url"),
|
||||
"token": structpb.NewStringValue("secret-token"),
|
||||
Attrs: &services.AuthenticateResponse_AuthTokenResponse{
|
||||
AuthTokenResponse: &authtokens.AuthToken{
|
||||
AccountId: "public-account_id",
|
||||
ApproximateLastUsedTime: timestamppb.New(now),
|
||||
AuthMethodId: "public-auth_method_id",
|
||||
AuthorizedActions: []string{
|
||||
"public-authorized_actions",
|
||||
},
|
||||
CreatedTime: timestamppb.New(now),
|
||||
ExpirationTime: timestamppb.New(now),
|
||||
Id: "public-id",
|
||||
ScopeId: "public-scope_id",
|
||||
Scope: &scopes.ScopeInfo{
|
||||
Id: "public-scope_id",
|
||||
Type: "public-scope_type",
|
||||
Name: "public-scope_name",
|
||||
Description: "public-scope_description",
|
||||
ParentScopeId: "public-parent_scope_id",
|
||||
},
|
||||
UpdatedTime: timestamppb.New(now),
|
||||
UserId: "public-user_id",
|
||||
Token: "secret-type",
|
||||
},
|
||||
},
|
||||
Type: "public-type",
|
||||
},
|
||||
},
|
||||
wantEvent: &eventlogger.Event{
|
||||
@@ -66,26 +74,31 @@ func TestAuthenticate_Tags(t *testing.T) {
|
||||
Payload: &services.AuthenticateResponse{
|
||||
Command: "public-command",
|
||||
// TODO(johanbrandhorst): update redaction once typed attributes are available
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"account_id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"approximate_last_used_time": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"auth_method_id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"authorized_actions": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"created_time": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"expiration_time": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"scope": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"type": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"updated_time": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"user_id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"status": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"auth_url": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"token_id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"final_redirect_url": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"token": structpb.NewStringValue(encrypt.RedactedData),
|
||||
Attrs: &services.AuthenticateResponse_AuthTokenResponse{
|
||||
AuthTokenResponse: &authtokens.AuthToken{
|
||||
AccountId: encrypt.RedactedData,
|
||||
ApproximateLastUsedTime: timestamppb.New(now),
|
||||
AuthMethodId: encrypt.RedactedData,
|
||||
AuthorizedActions: []string{
|
||||
encrypt.RedactedData,
|
||||
},
|
||||
CreatedTime: timestamppb.New(now),
|
||||
ExpirationTime: timestamppb.New(now),
|
||||
Id: encrypt.RedactedData,
|
||||
ScopeId: encrypt.RedactedData,
|
||||
Scope: &scopes.ScopeInfo{
|
||||
Id: "public-scope_id",
|
||||
Type: "public-scope_type",
|
||||
Name: "public-scope_name",
|
||||
Description: "public-scope_description",
|
||||
ParentScopeId: "public-parent_scope_id",
|
||||
},
|
||||
UpdatedTime: timestamppb.New(now),
|
||||
UserId: encrypt.RedactedData,
|
||||
Token: encrypt.RedactedData,
|
||||
},
|
||||
},
|
||||
Type: "public-type",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -98,14 +111,9 @@ func TestAuthenticate_Tags(t *testing.T) {
|
||||
AuthMethodId: "public-auth-method-id",
|
||||
TokenType: "public-token-type",
|
||||
Command: "public-command",
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"login_name": structpb.NewStringValue("public-login_name"),
|
||||
"auth_url": structpb.NewStringValue("public-auth_url"),
|
||||
"token_id": structpb.NewStringValue("public-token_id"),
|
||||
"state": structpb.NewStringValue("public-state"),
|
||||
"password": structpb.NewStringValue("secret-password"),
|
||||
"code": structpb.NewStringValue("secret-code"),
|
||||
Attrs: &services.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &authmethods.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: "public-token-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -118,14 +126,9 @@ func TestAuthenticate_Tags(t *testing.T) {
|
||||
TokenType: "public-token-type",
|
||||
Command: "public-command",
|
||||
// TODO(johanbrandhorst): update redaction once typed attributes are available
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"login_name": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"auth_url": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"token_id": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"state": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"password": structpb.NewStringValue(encrypt.RedactedData),
|
||||
"code": structpb.NewStringValue(encrypt.RedactedData),
|
||||
Attrs: &services.AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest{
|
||||
OidcAuthMethodAuthenticateTokenRequest: &authmethods.OidcAuthMethodAuthenticateTokenRequest{
|
||||
TokenId: encrypt.RedactedData,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -50,8 +50,6 @@ type AuthToken struct {
|
||||
ApproximateLastUsedTime *timestamppb.Timestamp `protobuf:"bytes,100,opt,name=approximate_last_used_time,proto3" json:"approximate_last_used_time,omitempty"`
|
||||
// Output only. The time this Auth Token expires.
|
||||
ExpirationTime *timestamppb.Timestamp `protobuf:"bytes,110,opt,name=expiration_time,proto3" json:"expiration_time,omitempty"`
|
||||
// Output only. The type of this auth token. Either "cookie" or "token".
|
||||
TokenType string `protobuf:"bytes,120,opt,name=token_type,proto3" json:"token_type,omitempty"`
|
||||
// Output only. The available actions on this resource for this user.
|
||||
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty"`
|
||||
}
|
||||
@@ -165,13 +163,6 @@ func (x *AuthToken) GetExpirationTime() *timestamppb.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AuthToken) GetTokenType() string {
|
||||
if x != nil {
|
||||
return x.TokenType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthToken) GetAuthorizedActions() []string {
|
||||
if x != nil {
|
||||
return x.AuthorizedActions
|
||||
@@ -193,7 +184,7 @@ var file_controller_api_resources_authtokens_v1_authtoken_proto_rawDesc = []byte
|
||||
0x6f, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70,
|
||||
0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x63, 0x6f, 0x70,
|
||||
0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x22, 0xe7, 0x04, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
|
||||
0x6f, 0x22, 0xc7, 0x04, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73,
|
||||
@@ -226,9 +217,7 @@ var file_controller_api_resources_authtokens_v1_authtoken_proto_rawDesc = []byte
|
||||
0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75,
|
||||
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
|
||||
0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x56, 0x5a, 0x54, 0x67,
|
||||
|
||||
Reference in new issue
Block a user