Skip to content

Commit

Permalink
module-transaction: Add support for initiating PAM Conversations
Browse files Browse the repository at this point in the history
Modules have the ability to start PAM conversations, so while the
transaction code can handle them we did not have a way to init them.
Yet.

So add some APIs allowing this, making it easier from the go side to
handle the conversations.

In this commit we only support text-based conversations, but code is
designed with the idea of supporting binary cases too.

Added the integration tests using the module that is now able to both
start conversation and handle them using Go only.
  • Loading branch information
3v1n0 committed Oct 9, 2023
1 parent 9d32c59 commit 429e941
Show file tree
Hide file tree
Showing 7 changed files with 481 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,34 @@ func (m *integrationTesterModule) handleRequest(authReq *authRequest, r *Request

var args []reflect.Value
for i, arg := range r.ActionArgs {
if arg == nil {
args = append(args, reflect.Zero(method.Type().In(i)))
} else {
args = append(args, reflect.ValueOf(arg))
switch v := arg.(type) {
case SerializableStringConvRequest:
args = append(args, reflect.ValueOf(
pam.NewStringConvRequest(v.Style, v.Request)))
default:
if arg == nil {
args = append(args, reflect.Zero(method.Type().In(i)))
} else {
args = append(args, reflect.ValueOf(arg))
}
}
}

res = &Result{Action: "return"}
for _, ret := range method.Call(args) {
iface := ret.Interface()
switch value := iface.(type) {
case pam.StringConvResponse:
res.ActionArgs = append(res.ActionArgs,
SerializableStringConvResponse{value.Style(), value.Response()})
case *pam.StringConvResponse:
if value != nil {
res.ActionArgs = append(res.ActionArgs,
SerializableStringConvResponse{value.Style(),
value.Response()})
} else {
res.ActionArgs = append(res.ActionArgs, nil)
}
case pam.ReturnType:
authReq.lastError = value
res.ActionArgs = append(res.ActionArgs, value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,13 +662,206 @@ func Test_Moduler_IntegrationTesterModule(t *testing.T) {
},
},
},
"start-conv-no-conv-set": {
expectedStatus: pam.ConvErr,
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.TextInfo,
"hello PAM!",
}),
exp: []interface{}{nil, pam.ConvErr},
},
{
r: NewRequest("StartStringConv", pam.TextInfo, "hello PAM!"),
exp: []interface{}{nil, pam.ConvErr},
},
},
},
"start-conv-prompt-text-info": {
expectedStatus: pam.Success,
credentials: utils.Credentials{
ExpectedMessage: "hello PAM!",
ExpectedStyle: pam.TextInfo,
TextInfo: "nice to see you, Go!",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.TextInfo,
"hello PAM!",
}),
exp: []interface{}{SerializableStringConvResponse{
pam.TextInfo,
"nice to see you, Go!",
}, nil},
},
{
r: NewRequest("StartStringConv", pam.TextInfo, "hello PAM!"),
exp: []interface{}{SerializableStringConvResponse{
pam.TextInfo,
"nice to see you, Go!",
}, nil},
},
{
r: NewRequest("StartStringConvf", pam.TextInfo, "hello %s!", "PAM"),
exp: []interface{}{SerializableStringConvResponse{
pam.TextInfo,
"nice to see you, Go!",
}, nil},
},
},
},
"start-conv-prompt-error-msg": {
expectedStatus: pam.Success,
credentials: utils.Credentials{
ExpectedMessage: "This is wrong, PAM!",
ExpectedStyle: pam.ErrorMsg,
ErrorMsg: "ops, sorry...",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.ErrorMsg,
"This is wrong, PAM!",
}),
exp: []interface{}{SerializableStringConvResponse{
pam.ErrorMsg,
"ops, sorry...",
}, nil},
},
{
r: NewRequest("StartStringConv", pam.ErrorMsg,
"This is wrong, PAM!",
),
exp: []interface{}{SerializableStringConvResponse{
pam.ErrorMsg,
"ops, sorry...",
}, nil},
},
{
r: NewRequest("StartStringConvf", pam.ErrorMsg,
"This is wrong, %s!", "PAM",
),
exp: []interface{}{SerializableStringConvResponse{
pam.ErrorMsg,
"ops, sorry...",
}, nil},
},
},
},
"start-conv-prompt-echo-on": {
expectedStatus: pam.Success,
credentials: utils.Credentials{
ExpectedMessage: "Give me your non-private infos",
ExpectedStyle: pam.PromptEchoOn,
EchoOn: "here's my public data",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.PromptEchoOn,
"Give me your non-private infos",
}),
exp: []interface{}{SerializableStringConvResponse{
pam.PromptEchoOn,
"here's my public data",
}, nil},
},
{
r: NewRequest("StartStringConv", pam.PromptEchoOn,
"Give me your non-private infos",
),
exp: []interface{}{SerializableStringConvResponse{
pam.PromptEchoOn,
"here's my public data",
}, nil},
},
},
},
"start-conv-prompt-echo-off": {
expectedStatus: pam.Success,
credentials: utils.Credentials{
ExpectedMessage: "Give me your super-secret data",
ExpectedStyle: pam.PromptEchoOff,
EchoOff: "here's my private token",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.PromptEchoOff,
"Give me your super-secret data",
}),
exp: []interface{}{SerializableStringConvResponse{
pam.PromptEchoOff,
"here's my private token",
}, nil},
},
{
r: NewRequest("StartStringConv", pam.PromptEchoOff,
"Give me your super-secret data",
),
exp: []interface{}{SerializableStringConvResponse{
pam.PromptEchoOff,
"here's my private token",
}, nil},
},
},
},
"start-conv-text-info-handle-failure-message-mismatch": {
expectedStatus: pam.ConvErr,
credentials: utils.Credentials{
ExpectedMessage: "This is an info message",
ExpectedStyle: pam.TextInfo,
TextInfo: "And this is what is returned",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.TextInfo,
"This should have been an info message, but is not",
}),
exp: []interface{}{nil, pam.ConvErr},
},
{
r: NewRequest("StartStringConv", pam.TextInfo,
"This should have been an info message, but is not",
),
exp: []interface{}{nil, pam.ConvErr},
},
},
},
"start-conv-text-info-handle-failure-style-mismatch": {
expectedStatus: pam.ConvErr,
credentials: utils.Credentials{
ExpectedMessage: "This is an info message",
ExpectedStyle: pam.PromptEchoOff,
TextInfo: "And this is what is returned",
},
checkedRequests: []checkedRequest{
{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.TextInfo,
"This is an info message",
}),
exp: []interface{}{nil, pam.ConvErr},
},
{
r: NewRequest("StartStringConv", pam.TextInfo,
"This is an info message",
),
exp: []interface{}{nil, pam.ConvErr},
},
},
},
}

for name, tc := range tests {
tc := tc
name := name
t.Run(name, func(t *testing.T) {
t.Parallel()

socketPath := filepath.Join(ts.WorkDir(), name+".socket")
ts.CreateService(name, []utils.ServiceLine{
{utils.Auth, utils.Requisite, modulePath, []string{socketPath}},
Expand Down Expand Up @@ -948,6 +1141,23 @@ func Test_Moduler_IntegrationTesterModule_Authenticate(t *testing.T) {
},
},
},
"StartConv": {
expectedStatus: pam.SystemErr,
checkedRequests: []checkedRequest{{
r: NewRequest("StartConv", SerializableStringConvRequest{
pam.TextInfo,
"hello PAM!",
}),
exp: []interface{}{nil, pam.SystemErr},
}},
},
"StartStringConv": {
expectedStatus: pam.SystemErr,
checkedRequests: []checkedRequest{{
r: NewRequest("StartStringConv", pam.TextInfo, "hello PAM!"),
exp: []interface{}{nil, pam.SystemErr},
}},
},
}

for name, tc := range tests {
Expand Down
16 changes: 16 additions & 0 deletions cmd/pam-moduler/tests/integration-tester-module/serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,28 @@ func (e *SerializableTransactionError) Error() string {
return e.Status().Error()
}

type SerializableStringConvRequest struct {
Style pam.Style
Request string
}

type SerializableStringConvResponse struct {
Style pam.Style
Response string
}

func init() {
gob.Register(map[string]string{})
gob.Register(Request{})
gob.Register(pam.Item(pam.Abort))
gob.Register(pam.Style(pam.TextInfo))
gob.Register(pam.ReturnType(pam.Success))
gob.Register([]pam.ConvResponse{})
gob.RegisterName("main.SerializableTransactionError",
SerializableTransactionError{})
gob.RegisterName("main.SerializableStringConvRequest",
SerializableStringConvRequest{})
gob.RegisterName("main.SerializableStringConvResponse",
SerializableStringConvResponse{})
gob.Register(utils.SerializableError{})
}
18 changes: 16 additions & 2 deletions cmd/pam-moduler/tests/internal/utils/test-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ func (e *SerializableError) Error() string {
type Credentials struct {
User string
Password string
EchoOn string
EchoOff string
TextInfo string
ErrorMsg string
ExpectedMessage string
CheckEmptyMessage bool
ExpectedStyle pam.Style
Expand Down Expand Up @@ -126,9 +130,19 @@ func (c Credentials) RespondPAM(s pam.Style, msg string) (string, error) {

switch s {
case pam.PromptEchoOn:
return c.User, nil
if c.User != "" {
return c.User, nil
}
return c.EchoOn, nil
case pam.PromptEchoOff:
return c.Password, nil
if c.Password != "" {
return c.Password, nil
}
return c.EchoOff, nil
case pam.TextInfo:
return c.TextInfo, nil
case pam.ErrorMsg:
return c.ErrorMsg, nil
}

return "", pam.NewTransactionError(
Expand Down
Loading

0 comments on commit 429e941

Please sign in to comment.