module-transaction: Add support for initiating PAM Conversations
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.
This commit is contained in:
@@ -56,10 +56,16 @@ 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +73,9 @@ func (m *integrationTesterModule) handleRequest(authReq *authRequest, r *Request
|
||||
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.Error:
|
||||
authReq.lastError = value
|
||||
res.ActionArgs = append(res.ActionArgs, value)
|
||||
|
||||
@@ -630,6 +630,194 @@ func Test_Moduler_IntegrationTesterModule(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"start-conv-no-conv-set": {
|
||||
expectedError: pam.ErrConv,
|
||||
checkedRequests: []checkedRequest{
|
||||
{
|
||||
r: NewRequest("StartConv", SerializableStringConvRequest{
|
||||
pam.TextInfo,
|
||||
"hello PAM!",
|
||||
}),
|
||||
exp: []interface{}{nil, pam.ErrConv},
|
||||
},
|
||||
{
|
||||
r: NewRequest("StartStringConv", pam.TextInfo, "hello PAM!"),
|
||||
exp: []interface{}{nil, pam.ErrConv},
|
||||
},
|
||||
},
|
||||
},
|
||||
"start-conv-prompt-text-info": {
|
||||
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": {
|
||||
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": {
|
||||
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": {
|
||||
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": {
|
||||
expectedError: pam.ErrConv,
|
||||
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.ErrConv},
|
||||
},
|
||||
{
|
||||
r: NewRequest("StartStringConv", pam.TextInfo,
|
||||
"This should have been an info message, but is not",
|
||||
),
|
||||
exp: []interface{}{nil, pam.ErrConv},
|
||||
},
|
||||
},
|
||||
},
|
||||
"start-conv-text-info-handle-failure-style-mismatch": {
|
||||
expectedError: pam.ErrConv,
|
||||
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.ErrConv},
|
||||
},
|
||||
{
|
||||
r: NewRequest("StartStringConv", pam.TextInfo,
|
||||
"This is an info message",
|
||||
),
|
||||
exp: []interface{}{nil, pam.ErrConv},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
@@ -880,6 +1068,23 @@ func Test_Moduler_IntegrationTesterModule_Authenticate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"StartConv": {
|
||||
expectedError: pam.ErrSystem,
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("StartConv", SerializableStringConvRequest{
|
||||
pam.TextInfo,
|
||||
"hello PAM!",
|
||||
}),
|
||||
exp: []interface{}{nil, pam.ErrSystem},
|
||||
}},
|
||||
},
|
||||
"StartStringConv": {
|
||||
expectedError: pam.ErrSystem,
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("StartStringConv", pam.TextInfo, "hello PAM!"),
|
||||
exp: []interface{}{nil, pam.ErrSystem},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
|
||||
@@ -24,12 +24,30 @@ func (e *SerializablePamError) Error() string {
|
||||
return e.RetStatus.Error()
|
||||
}
|
||||
|
||||
// SerializableStringConvRequest is a serializable string request.
|
||||
type SerializableStringConvRequest struct {
|
||||
Style pam.Style
|
||||
Request string
|
||||
}
|
||||
|
||||
// SerializableStringConvResponse is a serializable string response.
|
||||
type SerializableStringConvResponse struct {
|
||||
Style pam.Style
|
||||
Response string
|
||||
}
|
||||
|
||||
func init() {
|
||||
gob.Register(map[string]string{})
|
||||
gob.Register(Request{})
|
||||
gob.Register(pam.Item(0))
|
||||
gob.Register(pam.Error(0))
|
||||
gob.Register(pam.Style(0))
|
||||
gob.Register([]pam.ConvResponse{})
|
||||
gob.RegisterName("main.SerializablePamError",
|
||||
SerializablePamError{})
|
||||
gob.RegisterName("main.SerializableStringConvRequest",
|
||||
SerializableStringConvRequest{})
|
||||
gob.RegisterName("main.SerializableStringConvResponse",
|
||||
SerializableStringConvResponse{})
|
||||
gob.Register(utils.SerializableError{})
|
||||
}
|
||||
|
||||
@@ -118,6 +118,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
|
||||
@@ -145,9 +149,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 "", errors.Join(pam.ErrConv,
|
||||
|
||||
Reference in New Issue
Block a user