On Wed, Jan 13, 2016 at 12:42:31PM +0100, 'Oleg Ponomarev' via ganeti-devel
wrote:
> As proposed in doc/design-rapi-pam.rst, implement ValidateRequest
> function that interacts with PAM in order to perform authentication
> and then authorization.
>
> Signed-off-by: Oleg Ponomarev <[email protected]>
> ---
> Makefile.am | 1 +
> lib/errors.py | 6 +
> lib/rapi/auth/pam.py | 366
> ++++++++++++++++++++++++++++++++++++++++++++++++
> src/Ganeti/Constants.hs | 7 +
> 4 files changed, 380 insertions(+)
> create mode 100644 lib/rapi/auth/pam.py
> diff --git a/lib/rapi/auth/pam.py b/lib/rapi/auth/pam.py
> new file mode 100644
> index 0000000..edecbab
> --- /dev/null
> +++ b/lib/rapi/auth/pam.py
> @@ -0,0 +1,366 @@
> +#
> +#
> +
> +# Copyright (C) 2015 Google Inc.
s/2015/2015, 2016/
> +# All rights reserved.
> +#
> +def ValidateRequest(cf, username, uri_access_rights, password=None,
> + service=DEFAULT_SERVICE_NAME, authtok=None, uri=None,
> + method=None, body=None):
> + """Checks whether it's permitted to execute an rapi request.
> +
> + Calls pam_authenticate and then pam_acct_mgmt in order to check whether a
> + request should be executed.
> +
> + @param cf: An instance of CFunctions class containing necessary imports
> + @param username: username
> + @param uri_access_rights: handler access rights
> + @param password: password
> + @param service: a service name that will be used for the interaction with
> PAM
> + @param authtok: user's authentication token (e.g. some kind of signature)
> + @param uri: an uri of a target resource obtained from an http header
> + @param method: http method trying to access the uri
> + @param body: a body of an RAPI request
> +
> + """
> + ValidateParams(username, uri_access_rights, password, service, authtok,
> uri,
> + method, body)
> +
> + def ConversationFunction(num_msg, msg, resp, _app_data_ptr):
> + """Conversation function that will be provided to PAM modules.
> +
> + The function replies with a password for each message with
> + PAM_PROMPT_ECHO_OFF style and just ignores the others.
> +
> + """
> + if num_msg > MAX_MSG_COUNT:
> + logging.info("Too many messages passed to conv function: [%d]",
> num_msg)
> + return PAM_BUF_ERR
> + response = cf.calloc(num_msg, c.sizeof(PamResponse))
> + if not response:
> + logging.info("calloc failed in conv function")
s/info/warning/
> + return PAM_BUF_ERR
> + resp[0] = c.cast(response, c.POINTER(PamResponse))
> + for i in range(num_msg):
> + if msg[i].contents.msg_style != PAM_PROMPT_ECHO_OFF:
> + continue
> + resp.contents[i].resp = cf.strndup(password, len(password))
> + if not resp.contents[i].resp:
> + logging.info("strndup failed in conv function")
s/info/warning/
> + for j in range(i):
> + cf.free(c.cast(resp.contents[j].resp, c.c_void_p))
> + cf.free(response)
> + return PAM_BUF_ERR
> + resp.contents[i].resp_retcode = 0
> + return PAM_SUCCESS
> +
> + pam_handle = PamHandleT()
> + conv = PamConv(CONV_FUNC(ConversationFunction), 0)
> + ret = cf.pam_start(service, username, c.pointer(conv),
> c.pointer(pam_handle))
> + if ret != PAM_SUCCESS:
> + cf.pam_end(pam_handle, ret)
> + raise http.HttpInternalServerError("pam_start call failed [%d]" % ret)
> +
> + Authenticate(cf, pam_handle, authtok)
> + Authorize(cf, pam_handle, uri_access_rights, uri, method, body)
> +
> + cf.pam_end(pam_handle, PAM_SUCCESS)
Rest LGTM
--
Klaus Aehlig
Google Germany GmbH, Dienerstr. 12, 80331 Muenchen
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschaeftsfuehrer: Matthew Scott Sucherman, Paul Terence Manicle