def run(self): grants = keymanager.get_grants() try: roles = [x for x in iam.roles.all()] except ClientError: log.error('Failed to fetch IAM roles.') return services = [] for service in Service.data_type_date_index.query('service'): services.append(service.id) for role in roles: if role.name in services: log.info('Managing grants for {0}.'.format(role.name)) keymanager._ensure_grants(role, grants) log.info('Finished managing grants.')
def ensure_grants(id): try: _service = Service.get(id) if _service.data_type != 'service': msg = 'id provided is not a service.' return jsonify({'error': msg}), 400 except Service.DoesNotExist: msg = 'id provided does not exist.' return jsonify({'error': msg}), 400 try: keymanager.ensure_grants(id) except keymanager.ServiceCreateGrantError: msg = 'Failed to add grants for service.' log.error(msg) return jsonify({'error': msg}), 400 try: grants = keymanager.grants_exist(id) except keymanager.ServiceGetGrantError: msg = 'Failed to get grants.' return jsonify({'error': msg}), 500 return jsonify({'id': id, 'grants': grants})
def ensure_grants(id): try: _service = Service.get(id) if _service.data_type != 'service': msg = 'id provided is not a service.' return jsonify({'error': msg}), 400 except Service.DoesNotExist: msg = 'id provided does not exist.' return jsonify({'error': msg}), 400 try: keymanager.ensure_grants(id) except keymanager.ServiceCreateGrantError: msg = 'Failed to add grants for service.' log.error(msg) return jsonify({'error': msg}), 400 try: grants = keymanager.grants_exist(id) except keymanager.ServiceGetGrantError: msg = 'Failed to get grants.' return jsonify({'error': msg}), 500 return jsonify({ 'id': id, 'grants': grants })
def decorated(*args, **kwargs): if not app.config.get('USE_AUTH'): return f(*args, **kwargs) auth = request.authorization headers = request.headers using_basic_kms_auth = (auth and auth.get('username') and auth.get('password') != '') using_kms_auth = ('X-Auth-Token' in headers and 'X-Auth-From' in headers) # User suppplied basic auth info if using_basic_kms_auth or using_kms_auth: if using_basic_kms_auth: _from = auth['username'] token = auth['password'] else: _from = headers['X-Auth-From'] token = headers['X-Auth-Token'] try: with stats.timer('decrypt_token'): payload = keymanager.decrypt_token(token, _from) log.debug('Auth request had the following payload:' ' {0}'.format(payload)) role = 'service' msg = 'Authenticated {0} with role {1} via kms auth' msg = msg.format(_from, role) log.debug(msg) if role_has_privilege(role, f.func_name): g.auth_role = role g.username = _from return f(*args, **kwargs) else: msg = '{0} is not authorized to access {1}.' msg = msg.format(_from, f.func_name) log.warning(msg) return abort(403) except keymanager.TokenDecryptionError: msg = 'Access denied for {0}. Authentication Failed.' msg = msg.format(_from) log.warning(msg) return abort(403) # If not using kms auth, require google auth. else: role = 'user' if not role_has_privilege(role, f.func_name): return abort(403) if 'email' in session.get('google_oauth2', []): if (app.config['USERS_FILE'] and get_logged_in_user_email() not in users): msg = 'User not authorized: {0}' log.warning(msg.format(get_logged_in_user_email())) return abort(403) else: g.auth_role = role return f(*args, **kwargs) response = make_response() if request.is_secure: secure_cookie = True else: secure_cookie = False result = _authomatic.login( WerkzeugAdapter(request, response), 'google', session=session, session_saver=lambda: app.save_session(session, response), secure_cookie=secure_cookie) if result: if result.error: msg = 'Google auth failed with error: {0}' log.error(msg.format(result.error.message)) return abort(403) if result.user: result.user.update() user = result.user email_suffix = app.config['GOOGLE_AUTH_EMAIL_SUFFIX'] if email_suffix and not user.email.endswith(email_suffix): return abort(403) session['google_oauth2'] = {} session['google_oauth2']['email'] = user.email session['google_oauth2']['first_name'] = user.first_name session['google_oauth2']['last_name'] = user.last_name g.auth_role = role # TODO: find a way to save the angular args # authomatic adds url params google auth has stripped the # angular args anyway, so let's just redirect back to the # index. return redirect(url_for('index')) return response return abort(403)
def update_credential(id): try: _cred = Credential.get(id) except Credential.DoesNotExist: return jsonify({'error': 'Credential not found.'}), 404 if _cred.data_type != 'credential': msg = 'id provided is not a credential.' return jsonify({'error': msg}), 400 data = request.get_json() update = {} revision = _cred.revision + 1 update['name'] = data.get('name', _cred.name) if 'enabled' in data: if not isinstance(data['enabled'], bool): return jsonify({'error': 'Enabled must be a boolean.'}), 400 update['enabled'] = data['enabled'] else: update['enabled'] = _cred.enabled services = _get_services_for_credential(id) if 'credential_pairs' in data: # Ensure credential pair keys are lowercase credential_pairs = _lowercase_credential_pairs( data['credential_pairs'] ) if not _check_credential_pair_uniqueness(credential_pairs): ret = {'error': 'credential pairs must be key: value'} return jsonify(ret), 400 # Ensure credential pairs don't conflicts with pairs from other # services conflicts = _pair_key_conflicts_for_services( id, credential_pairs, services ) if conflicts: ret = { 'error': 'Conflicting key pairs in mapped service.', 'conflicts': conflicts } return jsonify(ret), 400 update['credential_pairs'] = json.dumps(credential_pairs) else: data_key = keymanager.decrypt_key( _cred.data_key, encryption_context={'id': id} ) cipher_version = _cred.cipher_version cipher = CipherManager(data_key, cipher_version) update['credential_pairs'] = cipher.decrypt(_cred.credential_pairs) data_key = keymanager.create_datakey(encryption_context={'id': id}) cipher = CipherManager(data_key['plaintext'], version=2) credential_pairs = cipher.encrypt(update['credential_pairs']) # Try to save to the archive try: Credential( id='{0}-{1}'.format(id, revision), name=update['name'], data_type='archive-credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email() ).save(id__null=True) except PutError as e: log.error(e) return jsonify({'error': 'Failed to add credential to archive.'}), 500 try: cred = Credential( id=id, name=update['name'], data_type='credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email() ) cred.save() except PutError as e: log.error(e) return jsonify({'error': 'Failed to update active credential.'}), 500 if services: service_names = [x.id for x in services] msg = 'Updated credential "{0}" ({1}); Revision {2}' msg = msg.format(cred.name, cred.id, cred.revision) graphite.send_event(service_names, msg) return jsonify({ 'id': cred.id, 'name': cred.name, 'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)), 'revision': cred.revision, 'enabled': cred.enabled, 'modified_date': cred.modified_date, 'modified_by': cred.modified_by })
def map_service_credentials(id): data = request.get_json() try: _service = Service.get(id) if _service.data_type != 'service': msg = 'id provided is not a service.' return jsonify({'error': msg}), 400 revision = _service.revision + 1 _service_credential_ids = _service.credentials except Service.DoesNotExist: revision = 1 _service_credential_ids = [] if data.get('credentials'): conflicts = _pair_key_conflicts_for_credentials( copy.deepcopy(data['credentials']) ) if conflicts: ret = { 'error': 'Conflicting key pairs in mapped service.', 'conflicts': conflicts } return jsonify(ret), 400 # If this is the first revision, we should attempt to create a grant for # this service. if revision == 1: try: keymanager.ensure_grants(id) except keymanager.ServiceCreateGrantError: msg = 'Failed to add grants for {0}.'.format(id) log.error(msg) # Try to save to the archive try: Service( id='{0}-{1}'.format(id, revision), data_type='archive-service', credentials=data.get('credentials'), enabled=data.get('enabled'), revision=revision, modified_by=authnz.get_logged_in_user_email() ).save(id__null=True) except PutError as e: log.error(e) return jsonify({'error': 'Failed to add service to archive.'}), 500 try: service = Service( id=id, data_type='service', credentials=data['credentials'], enabled=data.get('enabled'), revision=revision, modified_by=authnz.get_logged_in_user_email() ) service.save() except PutError as e: log.error(e) return jsonify({'error': 'Failed to update active service.'}), 500 added = list(set(service.credentials) - set(_service_credential_ids)) removed = list(set(_service_credential_ids) - set(service.credentials)) msg = 'Added credentials: {0}; Removed credentials {1}; Revision {2}' msg = msg.format(added, removed, service.revision) graphite.send_event([id], msg) try: credentials = _get_credentials(service.credentials) except KeyError: return jsonify({'error': 'Decryption error.'}), 500 return jsonify({ 'id': service.id, 'credentials': credentials, 'revision': service.revision, 'enabled': service.enabled, 'modified_date': service.modified_date, 'modified_by': service.modified_by })
def update_credential(id): try: _cred = Credential.get(id) except Credential.DoesNotExist: return jsonify({'error': 'Credential not found.'}), 404 if _cred.data_type != 'credential': msg = 'id provided is not a credential.' return jsonify({'error': msg}), 400 data = request.get_json() update = {} revision = _cred.revision + 1 update['name'] = data.get('name', _cred.name) if 'enabled' in data: if not isinstance(data['enabled'], bool): return jsonify({'error': 'Enabled must be a boolean.'}), 400 update['enabled'] = data['enabled'] else: update['enabled'] = _cred.enabled services = _get_services_for_credential(id) if 'credential_pairs' in data: # Ensure credential pair keys are lowercase credential_pairs = _lowercase_credential_pairs( data['credential_pairs']) if not _check_credential_pair_uniqueness(credential_pairs): ret = {'error': 'credential pairs must be key: value'} return jsonify(ret), 400 # Ensure credential pairs don't conflicts with pairs from other # services conflicts = _pair_key_conflicts_for_services(id, credential_pairs, services) if conflicts: ret = { 'error': 'Conflicting key pairs in mapped service.', 'conflicts': conflicts } return jsonify(ret), 400 update['credential_pairs'] = json.dumps(credential_pairs) else: data_key = keymanager.decrypt_key(_cred.data_key, encryption_context={'id': id}) cipher_version = _cred.cipher_version cipher = CipherManager(data_key, cipher_version) update['credential_pairs'] = cipher.decrypt(_cred.credential_pairs) data_key = keymanager.create_datakey(encryption_context={'id': id}) cipher = CipherManager(data_key['plaintext'], version=2) credential_pairs = cipher.encrypt(update['credential_pairs']) # Try to save to the archive try: Credential( id='{0}-{1}'.format(id, revision), name=update['name'], data_type='archive-credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email()).save(id__null=True) except PutError as e: log.error(e) return jsonify({'error': 'Failed to add credential to archive.'}), 500 try: cred = Credential(id=id, name=update['name'], data_type='credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email()) cred.save() except PutError as e: log.error(e) return jsonify({'error': 'Failed to update active credential.'}), 500 if services: service_names = [x.id for x in services] msg = 'Updated credential "{0}" ({1}); Revision {2}' msg = msg.format(cred.name, cred.id, cred.revision) graphite.send_event(service_names, msg) return jsonify({ 'id': cred.id, 'name': cred.name, 'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)), 'revision': cred.revision, 'enabled': cred.enabled, 'modified_date': cred.modified_date, 'modified_by': cred.modified_by })
def map_service_credentials(id): data = request.get_json() try: _service = Service.get(id) if _service.data_type != 'service': msg = 'id provided is not a service.' return jsonify({'error': msg}), 400 revision = _service.revision + 1 _service_credential_ids = _service.credentials except Service.DoesNotExist: revision = 1 _service_credential_ids = [] if data.get('credentials'): conflicts = _pair_key_conflicts_for_credentials( copy.deepcopy(data['credentials'])) if conflicts: ret = { 'error': 'Conflicting key pairs in mapped service.', 'conflicts': conflicts } return jsonify(ret), 400 # If this is the first revision, we should attempt to create a grant for # this service. if revision == 1: try: keymanager.ensure_grants(id) except keymanager.ServiceCreateGrantError: msg = 'Failed to add grants for {0}.'.format(id) log.error(msg) # Try to save to the archive try: Service( id='{0}-{1}'.format(id, revision), data_type='archive-service', credentials=data.get('credentials'), enabled=data.get('enabled'), revision=revision, modified_by=authnz.get_logged_in_user_email()).save(id__null=True) except PutError as e: log.error(e) return jsonify({'error': 'Failed to add service to archive.'}), 500 try: service = Service(id=id, data_type='service', credentials=data['credentials'], enabled=data.get('enabled'), revision=revision, modified_by=authnz.get_logged_in_user_email()) service.save() except PutError as e: log.error(e) return jsonify({'error': 'Failed to update active service.'}), 500 added = list(set(service.credentials) - set(_service_credential_ids)) removed = list(set(_service_credential_ids) - set(service.credentials)) msg = 'Added credentials: {0}; Removed credentials {1}; Revision {2}' msg = msg.format(added, removed, service.revision) graphite.send_event([id], msg) try: credentials = _get_credentials(service.credentials) except KeyError: return jsonify({'error': 'Decryption error.'}), 500 return jsonify({ 'id': service.id, 'credentials': credentials, 'revision': service.revision, 'enabled': service.enabled, 'modified_date': service.modified_date, 'modified_by': service.modified_by })
def decorated(*args, **kwargs): if not app.config.get("USE_AUTH"): return f(*args, **kwargs) auth = request.authorization headers = request.headers using_basic_kms_auth = auth and auth.get("username") and auth.get("password") != "" using_kms_auth = "X-Auth-Token" in headers and "X-Auth-From" in headers # User suppplied basic auth info if using_basic_kms_auth or using_kms_auth: if using_basic_kms_auth: _from = auth["username"] token = auth["password"] else: _from = headers["X-Auth-From"] token = headers["X-Auth-Token"] try: with stats.timer("decrypt_token"): payload = keymanager.decrypt_token(token, _from) log.debug("Auth request had the following payload:" " {0}".format(payload)) role = "service" msg = "Authenticated {0} with role {1} via kms auth" msg = msg.format(_from, role) log.debug(msg) if role_has_privilege(role, f.func_name): g.auth_role = role g.username = _from return f(*args, **kwargs) else: msg = "{0} is not authorized to access {1}." msg = msg.format(_from, f.func_name) log.warning(msg) return abort(403) except keymanager.TokenDecryptionError: msg = "Access denied for {0}. Authentication Failed." msg = msg.format(_from) log.warning(msg) return abort(403) # If not using kms auth, require google auth. else: role = "user" if not role_has_privilege(role, f.func_name): return abort(403) if "email" in session.get("google_oauth2", []): if app.config["USERS_FILE"] and get_logged_in_user_email() not in users: msg = "User not authorized: {0}" log.warning(msg.format(get_logged_in_user_email())) return abort(403) else: g.auth_role = role return f(*args, **kwargs) response = make_response() if request.is_secure: secure_cookie = True else: secure_cookie = False result = _authomatic.login( WerkzeugAdapter(request, response), "google", session=session, session_saver=lambda: app.save_session(session, response), secure_cookie=secure_cookie, ) if result: if result.error: msg = "Google auth failed with error: {0}" log.error(msg.format(result.error.message)) return abort(403) if result.user: result.user.update() user = result.user email_suffix = app.config["GOOGLE_AUTH_EMAIL_SUFFIX"] if email_suffix and not user.email.endswith(email_suffix): return abort(403) session["google_oauth2"] = {} session["google_oauth2"]["email"] = user.email session["google_oauth2"]["first_name"] = user.first_name session["google_oauth2"]["last_name"] = user.last_name g.auth_role = role # TODO: find a way to save the angular args # authomatic adds url params google auth has stripped the # angular args anyway, so let's just redirect back to the # index. return redirect(url_for("index")) return response return abort(403)