def authenticate(self, *args, **kwargs): if not all([ django_settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, django_settings.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT, django_settings.SOCIAL_AUTH_SAML_SP_PRIVATE_KEY, django_settings.SOCIAL_AUTH_SAML_ORG_INFO, django_settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT, django_settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT, django_settings.SOCIAL_AUTH_SAML_ENABLED_IDPS ]): return None if not feature_enabled('enterprise_auth'): logger.error( "Unable to authenticate, license does not support SAML authentication" ) return None created = False try: user = User.objects.get(username=kwargs.get('username', '')) if user and not user.is_in_enterprise_category('saml'): return None except User.DoesNotExist: created = True user = super(SAMLAuth, self).authenticate(*args, **kwargs) if user and created: _decorate_enterprise_user(user, 'saml') return user
def update_user_teams(backend, details, user=None, *args, **kwargs): ''' Update team memberships for the given user based on mapping rules defined in settings. ''' if not user: return from awx.main.models import Organization, Team multiple_orgs = feature_enabled('multiple_organizations') team_map = backend.setting('TEAM_MAP') or {} for team_name, team_opts in team_map.items(): # Get or create the org to update. If the license only allows for one # org, always use the first active org, unless no org exists. if multiple_orgs: if 'organization' not in team_opts: continue org = Organization.objects.get_or_create(name=team_opts['organization'])[0] else: try: org = Organization.objects.order_by('pk')[0] except IndexError: continue # Update team members from expression(s). team = Team.objects.get_or_create(name=team_name, organization=org)[0] users_expr = team_opts.get('users', None) remove = bool(team_opts.get('remove', True)) _update_m2m_from_expression(user, team.member_role.members, users_expr, remove)
def update_user_orgs(backend, details, user=None, *args, **kwargs): ''' Update organization memberships for the given user based on mapping rules defined in settings. ''' if not user: return from awx.main.models import Organization multiple_orgs = feature_enabled('multiple_organizations') org_map = backend.setting('ORGANIZATION_MAP') or {} for org_name, org_opts in org_map.items(): # Get or create the org to update. If the license only allows for one # org, always use the first active org, unless no org exists. if multiple_orgs: org = Organization.objects.get_or_create(name=org_name)[0] else: try: org = Organization.objects.order_by('pk')[0] except IndexError: continue # Update org admins from expression(s). remove = bool(org_opts.get('remove', True)) admins_expr = org_opts.get('admins', None) remove_admins = bool(org_opts.get('remove_admins', remove)) _update_m2m_from_expression(user, org.admin_role.members, admins_expr, remove_admins) # Update org users from expression(s). users_expr = org_opts.get('users', None) remove_users = bool(org_opts.get('remove_users', remove)) _update_m2m_from_expression(user, org.member_role.members, users_expr, remove_users)
def authenticate(self, username, password): if not django_settings.RADIUS_SERVER: return None if not feature_enabled('enterprise_auth'): logger.error("Unable to authenticate, license does not support RADIUS authentication") return None return super(RADIUSBackend, self).authenticate(username, password)
def authenticate(self, username, password): if not django_settings.TACACSPLUS_HOST: return None if not feature_enabled('enterprise_auth'): logger.error( "Unable to authenticate, license does not support TACACS+ authentication" ) return None try: # Upstream TACACS+ client does not accept non-string, so convert if needed. auth = tacacs_plus.TACACSClient( django_settings.TACACSPLUS_HOST.encode('utf-8'), django_settings.TACACSPLUS_PORT, django_settings.TACACSPLUS_SECRET.encode('utf-8'), timeout=django_settings.TACACSPLUS_SESSION_TIMEOUT, ).authenticate( username.encode('utf-8'), password.encode('utf-8'), authen_type=tacacs_plus.TAC_PLUS_AUTHEN_TYPES[ django_settings.TACACSPLUS_AUTH_PROTOCOL], ) except Exception as e: logger.exception("TACACS+ Authentication Error: %s" % (e.message, )) return None if auth.valid: return _get_or_set_enterprise_user(username, password, 'tacacs+')
def check_permissions(self, request): ret = super(WorkflowsEnforcementMixin, self).check_permissions(request) if not feature_enabled('workflows') and request.method not in ( 'GET', 'OPTIONS', 'DELETE'): raise LicenseForbids( _('Your license does not allow use of workflows.')) return ret
def authenticate(self, username, password): if self.settings.START_TLS and ldap.OPT_X_TLS_REQUIRE_CERT in self.settings.CONNECTION_OPTIONS: # with python-ldap, if you want to set connection-specific TLS # parameters, you must also specify OPT_X_TLS_NEWCTX = 0 # see: https://stackoverflow.com/a/29722445 # see: https://stackoverflow.com/a/38136255 self.settings.CONNECTION_OPTIONS[ldap.OPT_X_TLS_NEWCTX] = 0 if not self.settings.SERVER_URI: return None if not feature_enabled('ldap'): logger.error( "Unable to authenticate, license does not support LDAP authentication" ) return None try: user = User.objects.get(username=username) if user and (not user.profile or not user.profile.ldap_dn): return None except User.DoesNotExist: pass try: for setting_name, type_ in [ ('GROUP_SEARCH', 'LDAPSearch'), ('GROUP_TYPE', 'LDAPGroupType'), ]: if getattr(self.settings, setting_name) is None: raise ImproperlyConfigured( "{} must be an {} instance.".format( setting_name, type_)) return super(LDAPBackend, self).authenticate(username, password) except Exception: logger.exception("Encountered an error authenticating to LDAP") return None
def get_user(self, user_id): if not self.settings.SERVER_URI: return None if not feature_enabled('ldap'): logger.error("Unable to get_user, license does not support LDAP authentication") return None return super(LDAPBackend, self).get_user(user_id)
def _update_org_from_attr(user, rel, attr, remove, remove_admins): from awx.main.models import Organization multiple_orgs = feature_enabled('multiple_organizations') org_ids = [] for org_name in attr: if multiple_orgs: org = Organization.objects.get_or_create(name=org_name)[0] else: try: org = Organization.objects.order_by('pk')[0] except IndexError: continue org_ids.append(org.id) getattr(org, rel).members.add(user) if remove: [o.member_role.members.remove(user) for o in Organization.objects.filter(Q(member_role__members=user) & ~Q(id__in=org_ids))] if remove_admins: [o.admin_role.members.remove(user) for o in Organization.objects.filter(Q(admin_role__members=user) & ~Q(id__in=org_ids))]
def check_permissions(self, request): ret = super(ActivityStreamEnforcementMixin, self).check_permissions(request) if not feature_enabled('activity_streams'): raise LicenseForbids( _('Your license does not allow use of the activity stream.')) return ret
def authenticate(self, username, password): if self.settings.START_TLS and ldap.OPT_X_TLS_REQUIRE_CERT in self.settings.CONNECTION_OPTIONS: # with python-ldap, if you want to set connection-specific TLS # parameters, you must also specify OPT_X_TLS_NEWCTX = 0 # see: https://stackoverflow.com/a/29722445 # see: https://stackoverflow.com/a/38136255 self.settings.CONNECTION_OPTIONS[ldap.OPT_X_TLS_NEWCTX] = 0 if not self.settings.SERVER_URI: return None if not feature_enabled('ldap'): logger.error( "Unable to authenticate, license does not support LDAP authentication" ) return None try: user = User.objects.get(username=username) if user and (not user.profile or not user.profile.ldap_dn): return None except User.DoesNotExist: pass try: return super(LDAPBackend, self).authenticate(username, password) except Exception: logger.exception("Encountered an error authenticating to LDAP") return None
def check_permissions(self, request): ret = super(SystemTrackingEnforcementMixin, self).check_permissions(request) if not feature_enabled('system_tracking'): raise LicenseForbids( _('Your license does not permit use of system tracking.')) return ret
def get_user(self, user_id): if not django_settings.RADIUS_SERVER: return None if not feature_enabled('enterprise_auth'): logger.error("Unable to get_user, license does not support RADIUS authentication") return None user = super(RADIUSBackend, self).get_user(user_id) if not user.has_usable_password(): return user
def get_user(self, user_id): if not all([django_settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, django_settings.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT, django_settings.SOCIAL_AUTH_SAML_SP_PRIVATE_KEY, django_settings.SOCIAL_AUTH_SAML_ORG_INFO, django_settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT, django_settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT, django_settings.SOCIAL_AUTH_SAML_ENABLED_IDPS]): return None if not feature_enabled('enterprise_auth'): logger.error("Unable to get_user, license does not support SAML authentication") return None return super(SAMLAuth, self).get_user(user_id)
def get_user(self, user_id): if not django_settings.TACACSPLUS_HOST: return None if not feature_enabled('enterprise_auth'): logger.error("Unable to get user, license does not support TACACS+ authentication") return None try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
def get(self, request, format=None): '''Return various sitewide configuration settings''' if request.user.is_superuser or request.user.is_system_auditor: license_data = get_license(show_key=True) else: license_data = get_license(show_key=False) if not license_data.get('valid_key', False): license_data = {} if license_data and 'features' in license_data and 'activity_streams' in license_data[ 'features']: # FIXME: Make the final setting value dependent on the feature? license_data['features'][ 'activity_streams'] &= settings.ACTIVITY_STREAM_ENABLED pendo_state = settings.PENDO_TRACKING_STATE if settings.PENDO_TRACKING_STATE in ( 'off', 'anonymous', 'detailed') else 'off' data = dict( time_zone=settings.TIME_ZONE, license_info=license_data, version=get_awx_version(), ansible_version=get_ansible_version(), eula=render_to_string("eula.md") if license_data.get('license_type', 'UNLICENSED') != 'open' else '', analytics_status=pendo_state, become_methods=PRIVILEGE_ESCALATION_METHODS, ) # If LDAP is enabled, user_ldap_fields will return a list of field # names that are managed by LDAP and should be read-only for users with # a non-empty ldap_dn attribute. if getattr(settings, 'AUTH_LDAP_SERVER_URI', None) and feature_enabled('ldap'): user_ldap_fields = ['username', 'password'] user_ldap_fields.extend( getattr(settings, 'AUTH_LDAP_USER_ATTR_MAP', {}).keys()) user_ldap_fields.extend( getattr(settings, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {}).keys()) data['user_ldap_fields'] = user_ldap_fields if request.user.is_superuser \ or request.user.is_system_auditor \ or Organization.accessible_objects(request.user, 'admin_role').exists() \ or Organization.accessible_objects(request.user, 'auditor_role').exists(): data.update( dict(project_base_dir=settings.PROJECTS_ROOT, project_local_paths=Project.get_local_path_choices(), custom_virtualenvs=get_custom_venv_choices())) elif JobTemplate.accessible_objects(request.user, 'admin_role').exists(): data['custom_virtualenvs'] = get_custom_venv_choices() return Response(data)
def get(self, request, format=None): ''' List supported API versions ''' v1 = reverse('api:api_v1_root_view', kwargs={'version': 'v1'}) v2 = reverse('api:api_v2_root_view', kwargs={'version': 'v2'}) data = OrderedDict() data['description'] = _('AWX REST API') data['current_version'] = v2 data['available_versions'] = dict(v1=v1, v2=v2) data['oauth2'] = drf_reverse('api:oauth_authorization_root_view') if feature_enabled('rebranding'): data['custom_logo'] = settings.CUSTOM_LOGO data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO return Response(data)
def authenticate(self, *args, **kwargs): if not all([django_settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, django_settings.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT, django_settings.SOCIAL_AUTH_SAML_SP_PRIVATE_KEY, django_settings.SOCIAL_AUTH_SAML_ORG_INFO, django_settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT, django_settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT, django_settings.SOCIAL_AUTH_SAML_ENABLED_IDPS]): return None if not feature_enabled('enterprise_auth'): logger.error("Unable to authenticate, license does not support SAML authentication") return None user = super(SAMLAuth, self).authenticate(*args, **kwargs) # Comes from https://github.com/omab/python-social-auth/blob/v0.2.21/social/backends/base.py#L91 if getattr(user, 'is_new', False): _decorate_enterprise_user(user, 'saml') elif user and not user.is_in_enterprise_category('saml'): return None return user
def handle(self, *args, **options): if not feature_enabled('system_tracking'): raise CommandError("The System Tracking feature is not enabled for your instance") cleanup_facts = CleanupFacts() if not all([options[GRANULARITY], options[OLDER_THAN]]): raise CommandError('Both --granularity and --older_than are required.') older_than = self.string_time_to_timestamp(options[OLDER_THAN]) granularity = self.string_time_to_timestamp(options[GRANULARITY]) if older_than is None: raise CommandError('--older_than invalid value "%s"' % options[OLDER_THAN]) if granularity is None: raise CommandError('--granularity invalid value "%s"' % options[GRANULARITY]) cleanup_facts.run(older_than, granularity, module=options['module'])
def update_user_teams_by_saml_attr(backend, details, user=None, *args, **kwargs): if not user: return from awx.main.models import Organization, Team from django.conf import settings multiple_orgs = feature_enabled('multiple_organizations') team_map = settings.SOCIAL_AUTH_SAML_TEAM_ATTR if team_map.get('saml_attr') is None: return saml_team_names = set( kwargs.get('response', {}).get('attributes', {}).get(team_map['saml_attr'], [])) team_ids = [] for team_name_map in team_map.get('team_org_map', []): team_name = team_name_map.get('team', '') if team_name in saml_team_names: if multiple_orgs: if not team_name_map.get('organization', ''): # Settings field validation should prevent this. logger.error( "organization name invalid for team {}".format( team_name)) continue org = Organization.objects.get_or_create( name=team_name_map['organization'])[0] else: try: org = Organization.objects.order_by('pk')[0] except IndexError: continue team = Team.objects.get_or_create(name=team_name, organization=org)[0] team_ids.append(team.id) team.member_role.members.add(user) if team_map.get('remove', True): [ t.member_role.members.remove(user) for t in Team.objects.filter( Q(member_role__members=user) & ~Q(id__in=team_ids)) ]
def _default_from_required_settings(self): from django.conf import settings try: backends = settings._awx_conf_settings._get_default('AUTHENTICATION_BACKENDS') except AttributeError: backends = self.REQUIRED_BACKEND_SETTINGS.keys() # Filter which authentication backends are enabled based on their # required settings being defined and non-empty. Also filter available # backends based on license features. for backend, required_settings in self.REQUIRED_BACKEND_SETTINGS.items(): if backend not in backends: continue required_feature = self.REQUIRED_BACKEND_FEATURE.get(backend, '') if not required_feature or feature_enabled(required_feature): if all([getattr(settings, rs, None) for rs in required_settings]): continue backends = filter(lambda x: x != backend, backends) return backends
def create(self, request, *args, **kwargs): """Create a new organzation. If there is already an organization and the license of this instance does not permit multiple organizations, then raise LicenseForbids. """ # Sanity check: If the multiple organizations feature is disallowed # by the license, then we are only willing to create this organization # if no organizations exist in the system. if (not feature_enabled('multiple_organizations') and self.model.objects.exists()): raise LicenseForbids( _('Your license only permits a single ' 'organization to exist.')) # Okay, create the organization as usual. return super(OrganizationList, self).create(request, *args, **kwargs)
def get_external_account(user): from django.conf import settings from awx.conf.license import feature_enabled account_type = None if getattr(settings, 'AUTH_LDAP_SERVER_URI', None) and feature_enabled('ldap'): try: if user.pk and user.profile.ldap_dn and not user.has_usable_password(): account_type = "ldap" except AttributeError: pass if (getattr(settings, 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', None) or getattr(settings, 'SOCIAL_AUTH_GITHUB_KEY', None) or getattr(settings, 'SOCIAL_AUTH_GITHUB_ORG_KEY', None) or getattr(settings, 'SOCIAL_AUTH_GITHUB_TEAM_KEY', None) or getattr(settings, 'SOCIAL_AUTH_SAML_ENABLED_IDPS', None)) and user.social_auth.all(): account_type = "social" if (getattr(settings, 'RADIUS_SERVER', None) or getattr(settings, 'TACACSPLUS_HOST', None)) and user.enterprise_auth.all(): account_type = "enterprise" return account_type
def update_user_orgs_by_saml_attr(backend, details, user=None, *args, **kwargs): if not user: return from awx.main.models import Organization from django.conf import settings multiple_orgs = feature_enabled('multiple_organizations') org_map = settings.SOCIAL_AUTH_SAML_ORGANIZATION_ATTR if org_map.get('saml_attr') is None: return attr_values = kwargs.get('response', {}).get('attributes', {}).get(org_map['saml_attr'], []) org_ids = [] for org_name in attr_values: if multiple_orgs: org = Organization.objects.get_or_create(name=org_name)[0] else: try: org = Organization.objects.order_by('pk')[0] except IndexError: continue org_ids.append(org.id) org.member_role.members.add(user) if org_map.get('remove', True): [ o.member_role.members.remove(user) for o in Organization.objects.filter( Q(member_role__members=user) & ~Q(id__in=org_ids)) ]