def POST(self, username): """ Manage user principals """ # LDAP authentication is_admin_auth, message = tools.ldap_authentification(SERVER_OPTS, admin=True) if not is_admin_auth: return tools.response_render(message, http_code='401 Unauthorized') pg_conn, message = TOOLS.pg_connection() if pg_conn is None: return tools.response_render(message, http_code='503 Service Unavailable') cur = pg_conn.cursor() payload, message = tools.data2map() if message: return tools.response_render(message, http_code='400 Bad Request') if 'add' not in payload and \ 'remove' not in payload and \ 'update' not in payload and \ 'purge' not in payload: return tools.response_render( '[ERROR] Unknown action', http_code='400 Bad Request') # Search if username exists values = {'username': username} cur.execute( """ SELECT NAME,PRINCIPALS,REALNAME FROM USERS WHERE NAME=(%(username)s) """, values) user = cur.fetchone() # If user dont exist if user is None: cur.close() pg_conn.close() return tools.response_render( "ERROR: {} doesn't exist".format(username), http_code='400 Bad Request') values['principals'] = user[1] for key, value in payload.items(): value = unquote_plus(value) if key == 'add': for principal in value.split(','): if constants.PATTERN_PRINCIPALS.match(principal) is None: return tools.response_render( "Error: principal doesn't match pattern {}".format( constants.PATTERN_PRINCIPALS.pattern), http_code='400 Bad Request') if values['principals']: values['principals'] += ',' + value else: values['principals'] = value elif key == 'remove': principals = values['principals'].split(',') for principal in value.split(','): if constants.PATTERN_PRINCIPALS.match(principal) is None: return tools.response_render( "Error: principal doesn't match pattern {}".format( constants.PATTERN_PRINCIPALS.pattern), http_code='400 Bad Request') if principal in principals: principals.remove(principal) values['principals'] = ','.join(principals) elif key == 'update': for principal in value.split(','): if constants.PATTERN_PRINCIPALS.match(principal) is None: return tools.response_render( "Error: principal doesn't match pattern {}".format( constants.PATTERN_PRINCIPALS.pattern), http_code='400 Bad Request') values['principals'] = value elif key == 'purge': values['principals'] = username list_membership, _ = tools.get_memberof( user[2], SERVER_OPTS) values['principals'] = tools.truncate_principals( values['principals'], list_membership, SERVER_OPTS) cur.execute( """ UPDATE USERS SET PRINCIPALS=(%(principals)s) WHERE NAME=(%(username)s) """, values) pg_conn.commit() cur.close() pg_conn.close() # Add LDAP principals values['principals'] = tools.merge_principals( values['principals'], list_membership, SERVER_OPTS) return tools.response_render( "OK: {} principals are '{}'".format(username, values['principals']))
def POST(self): """ Search user's principals by filter """ # LDAP authentication is_admin_auth, message = tools.ldap_authentification(SERVER_OPTS, admin=True) if not is_admin_auth: return tools.response_render(message, http_code='401 Unauthorized') pg_conn, message = TOOLS.pg_connection() if pg_conn is None: return tools.response_render(message, http_code='503 Service Unavailable') cur = pg_conn.cursor() payload, message = tools.data2map() if message: return tools.response_render(message, http_code='400 Bad Request') if 'filter' not in payload: return tools.response_render( '[ERROR] Unknown action', http_code='400 Bad Request') cur.execute( """ SELECT NAME,PRINCIPALS,REALNAME FROM USERS """) all_principals = cur.fetchall() pg_conn.commit() cur.close() pg_conn.close() if SERVER_OPTS['ldap']: ldap_conn, _ = tools.get_ldap_conn( SERVER_OPTS['ldap_host'], SERVER_OPTS['ldap_username'], SERVER_OPTS['ldap_password']) result = dict() for key, value in payload.items(): value = unquote_plus(value) if key == 'filter' and value == '': for name, custom_principals, realname in all_principals: if not isinstance(custom_principals, str): continue list_membership, _ = tools.get_memberof( realname, SERVER_OPTS, reuse=ldap_conn) result[name] = tools.merge_principals( custom_principals, list_membership, SERVER_OPTS).split(',') elif key == 'filter': for principal in value.split(','): for name, custom_principals, realname in all_principals: if not isinstance(custom_principals, str): continue list_membership, _ = tools.get_memberof( realname, SERVER_OPTS, reuse=ldap_conn) principals = tools.merge_principals( custom_principals, list_membership, SERVER_OPTS).split(',') if principal in principals: if name not in result: result[name] = list() result[name].append(principal) return tools.response_render(dumps(result))
def POST(self): """ Ask to sign pub key. /client username=xxxxxx => Unique username. Used by default to connect on server. [email protected] => This LDAP/AD user. # Optionnal admin_force=true|false """ # LDAP authentication is_auth, message = tools.ldap_authentification(SERVER_OPTS) if not is_auth: return tools.response_render(message, http_code='401 Unauthorized') # Check if user is an admin and want to force signature when db fail force_sign = False # LDAP ADMIN authentication is_admin_auth, message = tools.ldap_authentification( SERVER_OPTS, admin=True) payload, message = tools.data2map() if message: return tools.response_render(message, http_code='400 Bad Request') if is_admin_auth and SERVER_OPTS['admin_db_failover'] \ and 'admin_force' in payload and payload['admin_force'].lower() == 'true': force_sign = True # Get username if 'username' in payload: username = payload['username'] else: return tools.response_render( 'Error: No username option given.', http_code='400 Bad Request') if username == 'all': return tools.response_render( "Error: username not valid.", http_code='400 Bad Request') # Get realname if 'realname' in payload: realname = unquote_plus(payload['realname']) else: return tools.response_render( 'Error: No realname option given.', http_code='400 Bad Request') # Get public key if 'pubkey' in payload: pubkey = tools.unquote_custom(payload['pubkey']) else: return tools.response_render( 'Error: No pubkey given.', http_code='400 Bad Request') tmp_pubkey = NamedTemporaryFile(delete=False) tmp_pubkey.write(bytes(pubkey, 'utf-8')) tmp_pubkey.close() pubkey_fingerprint = get_fingerprint(tmp_pubkey.name) if pubkey_fingerprint == 'Unknown': remove(tmp_pubkey.name) return tools.response_render( 'Error : Public key unprocessable', http_code='422 Unprocessable Entity') pg_conn, message = TOOLS.pg_connection() # Admin force signature case if pg_conn is None and force_sign: cert_contents = TOOLS.sign_key(tmp_pubkey.name, username, '+12h', username) remove(tmp_pubkey.name) return tools.response_render(cert_contents, content_type='application/octet-stream') # Check if db is up if pg_conn is None: remove(tmp_pubkey.name) return tools.response_render(message, http_code='503 Service Unavailable') cur = pg_conn.cursor() # Search if user already exists cur.execute( """ SELECT NAME,REALNAME,STATE,EXPIRY,PRINCIPALS,SSH_KEY FROM USERS WHERE NAME=lower(%s) """, (username,)) user = cur.fetchone() if user is None: cur.close() pg_conn.close() remove(tmp_pubkey.name) return tools.response_render( 'Error : User absent, please create an account.', http_code='400 Bad Request') # Get database key fingerprint db_pubkey = NamedTemporaryFile(delete=False) db_pubkey.write(bytes(user[5], 'utf-8')) db_pubkey.close() db_pubkey_fingerprint = get_fingerprint(db_pubkey.name) remove(db_pubkey.name) if db_pubkey_fingerprint == 'Unknown': remove(tmp_pubkey.name) return tools.response_render( 'Error : Public key from database unprocessable', http_code='422 Unprocessable Entity') if username != user[0] or \ realname != user[1] or \ db_pubkey_fingerprint != pubkey_fingerprint: cur.close() pg_conn.close() remove(tmp_pubkey.name) return tools.response_render( 'Error : (username, realname, pubkey) triple mismatch.', http_code='401 Unauthorized') status = user[2] expiry = user[3] custom_principals = tools.clean_principals_output(user[4], username, shell=True) list_membership, _ = tools.get_memberof( realname, SERVER_OPTS) full_principals = tools.merge_principals(custom_principals, list_membership, SERVER_OPTS) if status > 0: cur.close() pg_conn.close() remove(tmp_pubkey.name) return tools.response_render("Status: %s" % constants.STATES[user[2]]) cert_contents = TOOLS.sign_key( tmp_pubkey.name, username, expiry, full_principals, db_cursor=cur) remove(tmp_pubkey.name) pg_conn.commit() cur.close() pg_conn.close() return tools.response_render( cert_contents, content_type='application/octet-stream')