auth: Pass request dict instead of single values

parent 8a441805
...@@ -30,6 +30,8 @@ QUEUE_NAME_CERTS = "csr" ...@@ -30,6 +30,8 @@ QUEUE_NAME_CERTS = "csr"
CERTS_EXTRA_PARAMS = ("csr_str",) CERTS_EXTRA_PARAMS = ("csr_str",)
ACTION_CERTS = "certs"
class AuthStateMissing(Exception): class AuthStateMissing(Exception):
pass pass
...@@ -44,6 +46,15 @@ def build_reply_auth_accepted(delay=DELAY_AUTH): ...@@ -44,6 +46,15 @@ def build_reply_auth_accepted(delay=DELAY_AUTH):
} }
def build_reply_auth_start(sid, nonce):
return {
"status": "authenticate",
"sid": sid,
"nonce": nonce,
"message": "Authenticate yourself by sending digest and auth_type in 'auth' request"
}
def build_reply_get_wait(delay=DELAY_GET_SESSION_EXISTS): def build_reply_get_wait(delay=DELAY_GET_SESSION_EXISTS):
return { return {
"status": "wait", "status": "wait",
...@@ -78,30 +89,25 @@ def get_cert_key(sn): ...@@ -78,30 +89,25 @@ def get_cert_key(sn):
return "certificate:{}".format(sn) return "certificate:{}".format(sn)
def create_auth_session(sn, sid, csr_str, flags, auth_type, action, r): def create_auth_session(req, action, r, extra_params=()):
""" This function is called in case of `certs` when no certificate with """ This function is called in case of `certs` when no certificate with
matching private key is found in redis.. matching private key is found in redis.
Parameters "sn", "flags", "auth_type" and extra_params are required in
the req dictionary
""" """
current_app.logger.debug("Starting authentication for sn=%s", sn) current_app.logger.debug("Starting authentication for sn=%s", req["sn"])
sid = create_random_sid() sid = create_random_sid()
nonce = create_random_nonce() nonce = create_random_nonce()
session = {
"auth_type": auth_type, params = ("flags", "auth_type") + extra_params
"nonce": nonce, session = {i: req[i] for i in params}
"digest": "", session.update({"action": action, "nonce": nonce, "digest": ""})
"csr_str": csr_str,
"flags": flags, r.setex(get_session_key(req["sn"], sid),
"action": action,
}
r.setex(get_session_key(sn, sid),
current_app.config["REDIS_SESSION_TIMEOUT"], current_app.config["REDIS_SESSION_TIMEOUT"],
json.dumps(session)) json.dumps(session))
return { return build_reply_auth_start(sid, nonce)
"status": "authenticate",
"sid": sid,
"nonce": nonce,
"message": "Authenticate yourself by sending digest and auth_type in 'auth' request"
}
def check_auth_state(sn, sid, r): def check_auth_state(sn, sid, r):
...@@ -127,39 +133,42 @@ def check_auth_state(sn, sid, r): ...@@ -127,39 +133,42 @@ def check_auth_state(sn, sid, r):
raise RequestProcessError(auth_state["message"]) raise RequestProcessError(auth_state["message"])
def process_req_get_cert(sn, sid, csr_str, flags, auth_type, r): def process_req_get_cert(req, r):
current_app.logger.debug("Processing cert GET request, sn=%s, sid=%s", sn, sid) """ Parameters "sn", "sid", "cert_str", "auth_type" and "flags" are
if "renew" in flags: # when renew is flagged we ignore cert in redis required in the req dictionary.
return create_auth_session(sn, sid, csr_str, flags, auth_type, "certs", r) """
current_app.logger.debug("Processing cert GET request, sn=%s, sid=%s", req["sn"], req["sid"])
if "renew" in req["flags"]: # when renew is flagged we ignore cert in redis
return create_auth_session(req, ACTION_CERTS, r, CERTS_EXTRA_PARAMS)
authenticated = False authenticated = False
# We care about authentication only when session exists # We care about authentication only when session exists
if r.exists(get_session_key(sn, sid)): if r.exists(get_session_key(req["sn"], req["sid"])):
try: try:
check_auth_state(sn, sid, r) check_auth_state(req["sn"], req["sid"], r)
except AuthStateMissing: except AuthStateMissing:
return build_reply_get_wait() return build_reply_get_wait()
authenticated = True authenticated = True
cert_bytes = r.get(get_cert_key(sn)) cert_bytes = r.get(get_cert_key(req["sn"]))
if not cert_bytes: if not cert_bytes:
if authenticated: if authenticated:
current_app.logger.warning("Auth OK but certificate not in redis, sn=%s", sn) current_app.logger.warning("Auth OK but certificate not in redis, sn=%s", req["sn"])
else: else:
current_app.logger.debug("Certificate not in redis, sn=%s", sn) current_app.logger.debug("Certificate not in redis, sn=%s", req["sn"])
return create_auth_session(sn, sid, csr_str, flags, auth_type, "certs", r) return create_auth_session(req, ACTION_CERTS, r, CERTS_EXTRA_PARAMS)
current_app.logger.debug("Certificate found in redis, sn=%s", sn) current_app.logger.debug("Certificate found in redis, sn=%s", req["sn"])
# cert and csr public key match # cert and csr public key match
if not key_match(cert_bytes, csr_str.encode("utf-8")): if not key_match(cert_bytes, req["csr_str"].encode("utf-8")):
if authenticated: if authenticated:
current_app.logger.warning("Auth OK but certificate key does not match, sn=%s", sn) current_app.logger.warning("Auth OK but certificate key does not match, sn=%s", req["sn"])
else: else:
current_app.logger.debug("Certificate key does not match, sn=%s", sn) current_app.logger.debug("Certificate key does not match, sn=%s", req["sn"])
return create_auth_session(sn, sid, csr_str, flags, auth_type, r) return create_auth_session(req, ACTION_CERTS, r, CERTS_EXTRA_PARAMS)
current_app.logger.debug("Certificate restored from redis, sn=%s", sn) current_app.logger.debug("Certificate restored from redis, sn=%s", req["sn"])
return build_reply_get_ok(cert_bytes) return build_reply_get_ok(cert_bytes)
...@@ -207,30 +216,33 @@ def store_auth_params(sn, sid, session, queue_name, r, extra_params=()): ...@@ -207,30 +216,33 @@ def store_auth_params(sn, sid, session, queue_name, r, extra_params=()):
pipe.execute() pipe.execute()
def process_req_auth(sn, sid, digest, auth_type, action, r): def process_req_auth(req, action, r):
current_app.logger.debug("Processing AUTH request, sn=%s, sid=%s", sn, sid) """ Parameters "sn", "sid", "digest" and "auth_type" are
required in the req dictionary.
"""
current_app.logger.debug("Processing AUTH request, sn=%s, sid=%s", req["sn"], req["sid"])
session = get_auth_session(sn, sid, r) session = get_auth_session(req["sn"], req["sid"], r)
current_app.logger.debug("Authentication session found open for sn=%s, sid=%s", sn, sid) current_app.logger.debug("Authentication session found open for sn=%s, sid=%s", req["sn"], req["sid"])
if session["action"] != action: if session["action"] != action:
current_app.logger.debug("Action does not match, sn=%s, sid=%s", sn, sid) current_app.logger.debug("Action does not match, sn=%s, sid=%s", req["sn"], req["sid"])
raise RequestProcessError("Action does not match the original one") raise RequestProcessError("Action does not match the original one")
if session["auth_type"] != auth_type: if session["auth_type"] != req["auth_type"]:
current_app.logger.debug("Authentication type does not match, sn=%s, sid=%s", sn, sid) current_app.logger.debug("Authentication type does not match, sn=%s, sid=%s", req["sn"], req["sid"])
raise RequestProcessError("Auth type does not match the original one") raise RequestProcessError("Auth type does not match the original one")
if session["digest"]: # already authenticated if session["digest"]: # already authenticated
current_app.logger.debug("Digest already saved for sn=%s, sid=%s", sn, sid) current_app.logger.debug("Digest already saved for sn=%s, sid=%s", req["sn"], req["sid"])
raise RequestProcessError("Digest already saved") raise RequestProcessError("Digest already saved")
# store authentication parameters & tell the client to ask for result later # store authentication parameters & tell the client to ask for result later
current_app.logger.debug("Saving digest for sn=%s, sid=%s", sn, sid) current_app.logger.debug("Saving digest for sn=%s, sid=%s", req["sn"], req["sid"])
session["digest"] = digest session["digest"] = req["digest"]
if action == "certs": if action == "certs":
store_auth_params(sn, sid, session, QUEUE_NAME_CERTS, r, store_auth_params(req["sn"], req["sid"], session, QUEUE_NAME_CERTS, r,
CERTS_EXTRA_PARAMS) CERTS_EXTRA_PARAMS)
else: else:
raise CertAPISystemError("Unknown action {}".format(action)) raise CertAPISystemError("Unknown action {}".format(action))
...@@ -244,24 +256,22 @@ def process_request(req, r, action): ...@@ -244,24 +256,22 @@ def process_request(req, r, action):
if req["type"] == "get_cert" or req["type"] == "get": if req["type"] == "get_cert" or req["type"] == "get":
if action == "certs": if action == "certs":
return process_req_get_cert(req["sn"], req["csr_str"] = req["csr"] # stupid different naming in req and internals
req["sid"], return process_req_get_cert(req, r)
req["csr"],
req["flags"], raise CertAPISystemError("Unknown action {}".format(action)) # should not be raised here
req["auth_type"],
r)
raise CertAPISystemError("Unknown action {}".format(action))
elif req["type"] == "auth": elif req["type"] == "auth":
return process_req_auth(req["sn"], return process_req_auth(req, action, r)
req["sid"],
req["digest"], raise CertAPISystemError("Invalid request type {}".format(action)) # should not be raised here
req["auth_type"],
action,
r)
except RequestProcessError as e: except RequestProcessError as e:
return build_reply("fail", str(e)) return build_reply("fail", str(e))
except RequestConsistencyError as e: except RequestConsistencyError as e:
return build_reply("error", str(e)) return build_reply("error", str(e))
except CertAPISystemError as e: except CertAPISystemError as e:
current_app.logger.error(str(e)) current_app.logger.error(str(e))
return build_reply("error", "Sentinel error. Please, restart the process") return build_reply("error", "Sentinel error. Please, restart the process")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment