Import the files that were in the infra ansible repo
https://infrastructure.fedoraproject.org/infra/ansible/roles/ipsilon/files/ Signed-off-by: Aurélien Bompard <aurelien@bompard.org>
This commit is contained in:
parent
7e42976c1b
commit
fc9d0f5183
14 changed files with 2314 additions and 0 deletions
4
README.rst
Normal file
4
README.rst
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Ipsilon Fedora
|
||||
|
||||
This repository contains the Fedora-specific files that we use to extend
|
||||
Ipsilon.
|
10
install.sh
Executable file
10
install.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
PYDIR=`python3 -Ic "from distutils.sysconfig import get_python_lib; print(get_python_lib())"`
|
||||
|
||||
set -x
|
||||
|
||||
cp -afv ipsilon ${ROOT}${PYDIR}/
|
||||
cp -afv openid ${ROOT}${PYDIR}/
|
202
ipsilon/info/infofas.py
Normal file
202
ipsilon/info/infofas.py
Normal file
|
@ -0,0 +1,202 @@
|
|||
# Copyright (C) 2014,2016 Ipsilon project Contributors, for license see COPYING
|
||||
|
||||
from ipsilon.info.common import InfoProviderBase, InfoProviderInstaller
|
||||
from ipsilon.util.plugin import PluginObject
|
||||
from ipsilon.util.policy import Policy
|
||||
from ipsilon.util import config as pconfig
|
||||
|
||||
from fedora.client.fas2 import AccountSystem
|
||||
|
||||
|
||||
try:
|
||||
import openid_cla.cla as cla
|
||||
|
||||
CLA_GROUPS = {
|
||||
'cla_click': cla.CLA_URI_FEDORA_CLICK,
|
||||
'cla_dell': cla.CLA_URI_FEDORA_DELL,
|
||||
'cla_done': cla.CLA_URI_FEDORA_DONE,
|
||||
'cla_fedora': cla.CLA_URI_FEDORA_FEDORA,
|
||||
'cla_fpca': cla.CLA_URI_FEDORA_FPCA,
|
||||
'cla_ibm': cla.CLA_URI_FEDORA_IBM,
|
||||
'cla_intel': cla.CLA_URI_FEDORA_INTEL,
|
||||
'cla_redhat': cla.CLA_URI_FEDORA_REDHAT,
|
||||
}
|
||||
except ImportError:
|
||||
CLA_GROUPS = dict()
|
||||
|
||||
fas_mapping = [
|
||||
['username', 'nickname'],
|
||||
['telephone', 'phone'],
|
||||
['country_code', 'country'],
|
||||
['human_name', 'fullname'],
|
||||
['email', 'email'],
|
||||
['timezone', 'timezone'],
|
||||
['ssh_key', 'ssh_key'],
|
||||
['gpg_keyid', 'gpg_keyid'],
|
||||
]
|
||||
|
||||
fas_mapper = Policy(fas_mapping)
|
||||
|
||||
aws_idp_arn = 'arn:aws:iam::125523088429:saml-provider/id.fedoraproject.org'
|
||||
aws_groups = {
|
||||
'aws-master': 'arn:aws:iam::125523088429:role/aws-master',
|
||||
'aws-iam': 'arn:aws:iam::125523088429:role/aws-iam',
|
||||
'aws-billing': 'arn:aws:iam::125523088429:role/aws-billing',
|
||||
'aws-atomic': 'arn:aws:iam::125523088429:role/aws-atomic',
|
||||
'aws-s3-readonly': 'arn:aws:iam::125523088429:role/aws-s3-readonly',
|
||||
'aws-fedoramirror': 'arn:aws:iam::125523088429:role/aws-fedoramirror',
|
||||
'aws-s3': 'arn:aws:iam::125523088429:role/aws-s3',
|
||||
'aws-cloud-poc': 'arn:aws:iam::125523088429:role/aws-cloud-poc',
|
||||
'aws-infra': 'arn:aws:iam::125523088429:role/aws-infra',
|
||||
'aws-docs': 'arn:aws:iam::125523088429:role/aws-docs',
|
||||
'aws-copr': 'arn:aws:iam::125523088429:role/aws-copr',
|
||||
'aws-centos': 'arn:aws:iam::125523088429:role/aws-centos',
|
||||
'aws-min': 'arn:aws:iam::125523088429:role/aws-min',
|
||||
'aws-fedora-ci': 'arn:aws:iam::125523088429:role/aws-fedora-ci',
|
||||
}
|
||||
|
||||
|
||||
def fas_make_userdata(fas_data):
|
||||
userdata, fas_extra = fas_mapper.map_attributes(fas_data)
|
||||
|
||||
# We need to split ssh keys by newline, since we can't send newlines
|
||||
if userdata.get('ssh_key'):
|
||||
userdata['ssh_key'] = userdata['ssh_key'].split('\n')
|
||||
|
||||
# compute and store groups and cla groups
|
||||
userdata['_groups'] = []
|
||||
userdata['_extras'] = {'fas': fas_extra, 'cla': []}
|
||||
for group in fas_data.get('approved_memberships', {}):
|
||||
if 'name' not in group:
|
||||
continue
|
||||
if group.get('group_type') == 'cla':
|
||||
if group['name'] in CLA_GROUPS:
|
||||
group_name = CLA_GROUPS[group['name']]
|
||||
else:
|
||||
group_name = group['name']
|
||||
userdata['_extras']['cla'].append(group_name)
|
||||
else:
|
||||
userdata['_groups'].append(group['name'])
|
||||
|
||||
userdata['_extras']['awsroles'] = []
|
||||
for group in userdata['_groups']:
|
||||
if group in aws_groups:
|
||||
userdata['_extras']['awsroles'].append(
|
||||
'%s,%s' % (aws_idp_arn, aws_groups[group]))
|
||||
|
||||
return userdata
|
||||
|
||||
|
||||
class InfoProvider(InfoProviderBase):
|
||||
|
||||
def __init__(self, *args):
|
||||
super(InfoProvider, self).__init__(*args)
|
||||
self._fas_client = None
|
||||
self.name = 'fas'
|
||||
self.description = """
|
||||
Info plugin that retrieves user data from FAS. """
|
||||
|
||||
self.new_config(
|
||||
self.name,
|
||||
pconfig.String(
|
||||
'FAS url',
|
||||
'The FAS Url.',
|
||||
'https://admin.fedoraproject.org/accounts/'),
|
||||
pconfig.String(
|
||||
'FAS Proxy client user Agent',
|
||||
'The User Agent presented to the FAS Server.',
|
||||
'Ipsilon v1.0'),
|
||||
pconfig.Condition(
|
||||
'FAS Insecure Auth',
|
||||
'If checked skips FAS server cert verification.',
|
||||
False),
|
||||
pconfig.String(
|
||||
'Bind Username',
|
||||
'Username to be used when retrieving info.',
|
||||
'ipsilondummy'),
|
||||
pconfig.String(
|
||||
'Bind Password',
|
||||
'Username to be used when retrieving info.',
|
||||
'Password')
|
||||
)
|
||||
|
||||
@property
|
||||
def fas_url(self):
|
||||
return self.get_config_value('FAS url')
|
||||
|
||||
@property
|
||||
def user_agent(self):
|
||||
return self.get_config_value('FAS Proxy client user Agent')
|
||||
|
||||
@property
|
||||
def insecure(self):
|
||||
return self.get_config_value('FAS Insecure Auth')
|
||||
|
||||
@property
|
||||
def bind_user(self):
|
||||
return self.get_config_value('Bind Username')
|
||||
|
||||
@property
|
||||
def bind_pass(self):
|
||||
return self.get_config_value('Bind Password')
|
||||
|
||||
@property
|
||||
def fas_client(self):
|
||||
if not self._fas_client:
|
||||
self._fas_client = AccountSystem(base_url=self.fas_url,
|
||||
insecure=self.insecure,
|
||||
useragent=self.user_agent,
|
||||
username=self.bind_user,
|
||||
password=self.bind_pass)
|
||||
return self._fas_client
|
||||
|
||||
def get_user_attrs(self, user):
|
||||
if not self.fas_client:
|
||||
return {}
|
||||
try:
|
||||
data = self.fas_client.person_by_username(user)
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
self.error('Unable to retrieve info for %s: %s' % (user, ex))
|
||||
self.debug('URL: %s' % self.fas_url)
|
||||
self.debug('username: %s' % self.bind_user)
|
||||
return {}
|
||||
if not data:
|
||||
return {}
|
||||
return fas_make_userdata(data)
|
||||
|
||||
|
||||
class Installer(InfoProviderInstaller):
|
||||
|
||||
def __init__(self, *pargs):
|
||||
super(Installer, self).__init__()
|
||||
self.name = 'fas'
|
||||
self.pargs = pargs
|
||||
|
||||
def install_args(self, group):
|
||||
group.add_argument('--info-fas', choices=['yes', 'no'], default='no',
|
||||
help='Configure FAS info')
|
||||
group.add_argument('--info-fas-bind-username', action='store',
|
||||
help='Username to use to retrieve FAS info')
|
||||
group.add_argument('--info-fas-bind-password', action='store',
|
||||
help='Password to use to retrieve FAS info')
|
||||
|
||||
def configure(self, opts, changes):
|
||||
if opts['info_fas'] != 'yes':
|
||||
return
|
||||
|
||||
# Add configuration data to database
|
||||
po = PluginObject(*self.pargs)
|
||||
po.name = 'fas'
|
||||
po.wipe_data()
|
||||
po.wipe_config_values()
|
||||
|
||||
config = dict()
|
||||
if 'info_fas_bind_username' in opts:
|
||||
config['Bind Username'] = opts['info_fas_bind_username']
|
||||
if 'info_fas_bind_password' in opts:
|
||||
config['Bind Password'] = opts['info_fas_bind_password']
|
||||
po.save_plugin_config(config)
|
||||
|
||||
# Update global config to add login plugin
|
||||
po.is_enabled = True
|
||||
po.save_enabled_state()
|
113
ipsilon/providers/openid/extensions/api.py
Normal file
113
ipsilon/providers/openid/extensions/api.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
# Copyright (C) 2015 Patrick Uiterwijk, for license see COPYING
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
try:
|
||||
from ipsilon.info.infofas import fas_make_userdata
|
||||
except ImportError:
|
||||
fas_make_userdata = None
|
||||
from ipsilon.providers.openid.extensions.common import OpenidExtensionBase
|
||||
import ipsilon.root
|
||||
from ipsilon.util.page import Page
|
||||
from ipsilon.util.user import User
|
||||
|
||||
import json
|
||||
import inspect
|
||||
|
||||
|
||||
class OpenidExtension(OpenidExtensionBase):
|
||||
|
||||
def __init__(self, *pargs):
|
||||
super(OpenidExtension, self).__init__('API')
|
||||
|
||||
def enable(self):
|
||||
# This is the most ugly hack in my history of python...
|
||||
# But I need to find the root object, and that is not passed into
|
||||
# the OpenID extension system anywhere...
|
||||
root_obj = inspect.stack()[5][0].f_locals['self']
|
||||
root_obj.api = APIPage(root_obj)
|
||||
|
||||
|
||||
class APIPage(Page):
|
||||
def __init__(self, root_obj):
|
||||
ipsilon.root.sites['api'] = dict()
|
||||
ipsilon.root.sites['api']['template_env'] = \
|
||||
ipsilon.root.sites['default']['template_env']
|
||||
super(APIPage, self).__init__(ipsilon.root.sites['api'])
|
||||
self.v1 = APIV1Page(root_obj)
|
||||
|
||||
|
||||
class APIV1Page(Page):
|
||||
def __init__(self, root_obj):
|
||||
ipsilon.root.sites['api_v1'] = dict()
|
||||
ipsilon.root.sites['api_v1']['template_env'] = \
|
||||
ipsilon.root.sites['default']['template_env']
|
||||
super(APIV1Page, self).__init__(ipsilon.root.sites['api_v1'])
|
||||
self.root_obj = root_obj
|
||||
|
||||
def root(self, *args, **kwargs):
|
||||
return json.dumps(self._perform_call(kwargs))
|
||||
|
||||
def _perform_call(self, arguments):
|
||||
required_arguments = ['auth_module', 'username', 'password']
|
||||
for arg in required_arguments:
|
||||
if not arg in arguments:
|
||||
return {'success': False,
|
||||
'status': 400,
|
||||
'message': 'Missing argument: %s' % arg
|
||||
}
|
||||
|
||||
fas = self.root_obj.login.fas.lm
|
||||
openid = self.root_obj.openid
|
||||
|
||||
openid_request = None
|
||||
try:
|
||||
openid_request = openid.cfg.server.decodeRequest(arguments)
|
||||
except Exception as ex:
|
||||
print('Error during openid decoding: %s' % ex)
|
||||
return {'success': False,
|
||||
'status': 400,
|
||||
'message': 'Invalid request'
|
||||
}
|
||||
if not openid_request:
|
||||
print('No OpenID request parsed')
|
||||
return {'success': False,
|
||||
'status': 400,
|
||||
'message': 'Invalid request'
|
||||
}
|
||||
if not arguments['auth_module'] == 'fedoauth.auth.fas.Auth_FAS':
|
||||
print('Unknown auth module selected')
|
||||
return {'success': False,
|
||||
'status': 400,
|
||||
'message': 'Unknown authentication module'
|
||||
}
|
||||
username = arguments['username']
|
||||
password = arguments['password']
|
||||
user = None
|
||||
userdata = None
|
||||
try:
|
||||
_, user = fas.fpc.login(username, password)
|
||||
if fas_make_userdata is None:
|
||||
userdata = fas.page.make_userdata(user.user)
|
||||
else:
|
||||
userdata = fas_make_userdata(user.user)
|
||||
except Exception as ex:
|
||||
print('Error during auth: %s' % ex)
|
||||
pass
|
||||
|
||||
if user is None or userdata is None:
|
||||
print('No user or data: %s, %s' % (user, userdata))
|
||||
return {'success': False,
|
||||
'status': 400,
|
||||
'message': 'Authentication failed'}
|
||||
|
||||
us_obj = User(username)
|
||||
fake_session = lambda: None
|
||||
setattr(fake_session, 'get_user', lambda *args: us_obj)
|
||||
setattr(fake_session, 'get_user_attrs', lambda *args: userdata)
|
||||
|
||||
openid_response = openid._response(openid_request, fake_session)
|
||||
openid_response = openid.cfg.server.signatory.sign(openid_response).fields.toPostArgs()
|
||||
return {'success': True,
|
||||
'response': openid_response}
|
||||
|
22
ipsilon/providers/openidc/plugins/account-scopes.py
Normal file
22
ipsilon/providers/openidc/plugins/account-scopes.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'fedora-account'
|
||||
display_name = 'Fedora Account Information'
|
||||
scopes = {
|
||||
'fedora': { # NOTE: This is temporary! DO NOT USE IN NEW PROJECTS!
|
||||
'display_name': 'Fedora',
|
||||
'claims': ['cla', 'zoneinfo', 'groups']
|
||||
},
|
||||
'https://id.fedoraproject.org/scope/groups': {
|
||||
'display_name': 'Fedora Account Groups list',
|
||||
'claims': ['groups']
|
||||
},
|
||||
'https://id.fedoraproject.org/scope/cla': {
|
||||
'display_name': 'Fedora Account CLA status',
|
||||
'claims': ['cla']
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/beaker.py
Normal file
14
ipsilon/providers/openidc/plugins/beaker.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'beaker'
|
||||
display_name = 'Beaker Jobs'
|
||||
scopes = {
|
||||
'https://beaker-project.org/oidc/scope': {
|
||||
'display_name': 'Full access to your beaker account',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
22
ipsilon/providers/openidc/plugins/fpdc.py
Normal file
22
ipsilon/providers/openidc/plugins/fpdc.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'fpdc'
|
||||
display_name = 'Fedora Product Definition Center'
|
||||
scopes = {
|
||||
'https://fpdc.fedoraproject.org/oidc/create-release': {
|
||||
'display_name': 'Create a Release record',
|
||||
'claims': [],
|
||||
},
|
||||
'https://fpdc.fedoraproject.org/oidc/update-release': {
|
||||
'display_name': 'Update a Release record',
|
||||
'claims': [],
|
||||
},
|
||||
'https://fpdc.fedoraproject.org/oidc/delete-release': {
|
||||
'display_name': 'Delete a Release record',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/kerneltest.py
Normal file
14
ipsilon/providers/openidc/plugins/kerneltest.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'kerneltest'
|
||||
display_name = 'Fedora Kernel tests'
|
||||
scopes = {
|
||||
'https://github.com/jmflinuxtx/kerneltest-harness/oidc/upload_test_run': {
|
||||
'display_name': 'Upload the results of a test run',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/mbs.py
Normal file
14
ipsilon/providers/openidc/plugins/mbs.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'mbs'
|
||||
display_name = 'Module Builds'
|
||||
scopes = {
|
||||
'https://mbs.fedoraproject.org/oidc/submit-build': {
|
||||
'display_name': 'Permission to submit new module builds',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
22
ipsilon/providers/openidc/plugins/odcs.py
Normal file
22
ipsilon/providers/openidc/plugins/odcs.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'odcs'
|
||||
display_name = 'On Demand Composes'
|
||||
scopes = {
|
||||
'https://pagure.io/odcs/new-compose': {
|
||||
'display_name': 'Permission to request new composes',
|
||||
'claims': [],
|
||||
},
|
||||
'https://pagure.io/odcs/renew-compose': {
|
||||
'display_name': 'Permission to renew the expiry on composes',
|
||||
'claims': [],
|
||||
},
|
||||
'https://pagure.io/odcs/delete-compose': {
|
||||
'display_name': 'Permission to delete composes',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/src.py
Normal file
14
ipsilon/providers/openidc/plugins/src.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'src'
|
||||
display_name = 'Dist-Git'
|
||||
scopes = {
|
||||
'https://src.fedoraproject.org/push': {
|
||||
'display_name': 'Push to Fedora Dist-Git',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/waiverdb.py
Normal file
14
ipsilon/providers/openidc/plugins/waiverdb.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'waiverdb'
|
||||
display_name = 'Waiver DB'
|
||||
scopes = {
|
||||
'https://waiverdb.fedoraproject.org/oidc/create-waiver': {
|
||||
'display_name': 'Permission to create new waivers',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
14
ipsilon/providers/openidc/plugins/wiki.py
Normal file
14
ipsilon/providers/openidc/plugins/wiki.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from ipsilon.providers.openidc.plugins.common import OpenidCExtensionBase
|
||||
|
||||
|
||||
class OpenidCExtension(OpenidCExtensionBase):
|
||||
name = 'wiki'
|
||||
display_name = 'Fedora Wiki'
|
||||
scopes = {
|
||||
'https://fedoraproject.org/wiki/api': {
|
||||
'display_name': 'Fedora Wiki API access',
|
||||
'claims': [],
|
||||
},
|
||||
}
|
1835
openid/server/server.py
Normal file
1835
openid/server/server.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue