diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a3358b8b..cf5d8a86 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,8 @@ is 30 days. Every certificate will gain a policy regardless is auto-rotation is Adds per-user API Keys, requires a database migration. +Adds third_party to roles for external authentication roles, requires a database migration. + .. note:: This version is not yet released and is under active development diff --git a/lemur/auth/ldap.py b/lemur/auth/ldap.py index e808a199..e72469a5 100644 --- a/lemur/auth/ldap.py +++ b/lemur/auth/ldap.py @@ -65,7 +65,7 @@ class LdapPrincipal(): else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: - if ur.authority_id: + if not ur.third_party: roles.add(ur) # update any changes to the user @@ -97,13 +97,18 @@ class LdapPrincipal(): if self.ldap_default_role: role = role_service.get_by_name(self.ldap_default_role) if role: + if not role.third_party: + role = role.set_third_party(role.id, third_party_status=True) roles.add(role) # update their 'roles' role = role_service.get_by_name(self.ldap_principal) if not role: description = "auto generated role based on owner: {0}".format(self.ldap_principal) - role = role_service.create(self.ldap_principal, description=description) + role = role_service.create(self.ldap_principal, description=description, + third_party=True) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.add(role) if not self.ldap_groups_to_roles: return roles @@ -113,6 +118,8 @@ class LdapPrincipal(): if role: if ldap_group_name in self.ldap_groups: current_app.logger.debug("assigning role {0} to ldap user {1}".format(self.ldap_principal, role)) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.add(role) return roles diff --git a/lemur/auth/views.py b/lemur/auth/views.py index 47d26d7b..af04d8c5 100644 --- a/lemur/auth/views.py +++ b/lemur/auth/views.py @@ -211,13 +211,17 @@ class Ping(Resource): for group in profile['googleGroups']: role = role_service.get_by_name(group) if not role: - role = role_service.create(group, description='This is a google group based role created by Lemur') + role = role_service.create(group, description='This is a google group based role created by Lemur', third_party=True) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.append(role) role = role_service.get_by_name(profile['email']) if not role: - role = role_service.create(profile['email'], description='This is a user specific role') + role = role_service.create(profile['email'], description='This is a user specific role', third_party=True) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.append(role) @@ -226,6 +230,8 @@ class Ping(Resource): default = role_service.get_by_name(current_app.config['LEMUR_DEFAULT_ROLE']) if not default: default = role_service.create(current_app.config['LEMUR_DEFAULT_ROLE'], description='This is the default Lemur role.') + if not default.third_party: + role_service.set_third_party(default.id, third_party_status=True) roles.append(default) # if we get an sso user create them an account @@ -242,7 +248,7 @@ class Ping(Resource): else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: - if ur.authority_id: + if not ur.third_party: roles.append(ur) # update any changes to the user @@ -352,12 +358,16 @@ class OAuth2(Resource): for group in profile['roles']: role = role_service.get_by_name(group) if not role: - role = role_service.create(group, description='This is a group configured by identity provider') + role = role_service.create(group, description='This is a group configured by identity provider', third_party=True) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.append(role) role = role_service.get_by_name(profile['email']) if not role: - role = role_service.create(profile['email'], description='This is a user specific role') + role = role_service.create(profile['email'], description='This is a user specific role', third_party=True) + if not role.third_party: + role = role_service.set_third_party(role.id, third_party_status=True) roles.append(role) # if we get an sso user create them an account @@ -365,6 +375,8 @@ class OAuth2(Resource): # every user is an operator (tied to a default role) if current_app.config.get('LEMUR_DEFAULT_ROLE'): v = role_service.get_by_name(current_app.config.get('LEMUR_DEFAULT_ROLE')) + if not v.third_party: + v = role_service.set_third_party(v.id, third_party_status=True) if v: roles.append(v) @@ -380,7 +392,7 @@ class OAuth2(Resource): else: # we add 'lemur' specific roles, so they do not get marked as removed for ur in user.roles: - if ur.authority_id: + if not ur.third_party: roles.append(ur) # update any changes to the user diff --git a/lemur/migrations/versions/5bc47fa7cac4_.py b/lemur/migrations/versions/5bc47fa7cac4_.py new file mode 100644 index 00000000..f4a145c8 --- /dev/null +++ b/lemur/migrations/versions/5bc47fa7cac4_.py @@ -0,0 +1,22 @@ +"""add third party roles to lemur + +Revision ID: 5bc47fa7cac4 +Revises: c05a8998b371 +Create Date: 2017-12-08 14:19:11.903864 + +""" + +# revision identifiers, used by Alembic. +revision = '5bc47fa7cac4' +down_revision = 'c05a8998b371' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('roles', sa.Column('third_party', sa.Boolean(), nullable=True, default=False)) + + +def downgrade(): + op.drop_column('roles', 'third_party') diff --git a/lemur/roles/models.py b/lemur/roles/models.py index b324360e..3ecd9188 100644 --- a/lemur/roles/models.py +++ b/lemur/roles/models.py @@ -10,7 +10,7 @@ """ from sqlalchemy.orm import relationship -from sqlalchemy import Column, Integer, String, Text, ForeignKey +from sqlalchemy import Boolean, Column, Integer, String, Text, ForeignKey from lemur.database import db from lemur.utils import Vault @@ -27,6 +27,7 @@ class Role(db.Model): authority_id = Column(Integer, ForeignKey('authorities.id')) authorities = relationship("Authority", secondary=roles_authorities, passive_deletes=True, backref="role", cascade='all,delete') user_id = Column(Integer, ForeignKey('users.id')) + third_party = Column(Boolean) users = relationship("User", secondary=roles_users, passive_deletes=True, backref="role") certificates = relationship("Certificate", secondary=roles_certificates, backref="role") diff --git a/lemur/roles/schemas.py b/lemur/roles/schemas.py index 246f5828..bbeb8ef7 100644 --- a/lemur/roles/schemas.py +++ b/lemur/roles/schemas.py @@ -26,6 +26,7 @@ class RoleOutputSchema(LemurOutputSchema): id = fields.Integer() name = fields.String() description = fields.String() + third_party = fields.Boolean() authorities = fields.Nested(AuthorityNestedOutputSchema, many=True) users = fields.Nested(UserNestedOutputSchema, many=True) diff --git a/lemur/roles/service.py b/lemur/roles/service.py index 248e34ca..352ebf1f 100644 --- a/lemur/roles/service.py +++ b/lemur/roles/service.py @@ -32,7 +32,22 @@ def update(role_id, name, description, users): return role -def create(name, password=None, description=None, username=None, users=None): +def set_third_party(role_id, third_party_status=False): + """ + Sets a role to be a third party role. A user should pretty much never + call this directly. + + :param role_id: + :param third_party_status: + :return: + """ + role = get(role_id) + role.third_party = third_party_status + database.update(role) + return role + + +def create(name, password=None, description=None, username=None, users=None, third_party=False): """ Create a new role @@ -43,7 +58,7 @@ def create(name, password=None, description=None, username=None, users=None): :param password: :return: """ - role = Role(name=name, description=description, username=username, password=password) + role = Role(name=name, description=description, username=username, password=password, third_party=third_party) if users: role.users = users