How can we automate the creation of a third party OAuth Identity Provider without using the web ui?
We want to install and configure tutor on a clean server from without configuring it manually using the web ui. We have nearly succeeded, automating deployments from gitlab ci but we can’t automate the identity provider creation.
Do I need to make a Django plugin app? If so how do I get started? Is there documentation already present? I only understand tutor plugins so that’s what I tried but this doesn’t work:
import os
from tutor import hooks
def setup_django_environment():
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.envs.production")
django.setup()
def create_oauth_app_client():
setup_django_environment()
from oauth2_provider.models import Application
from django.contrib.sites.models import Site
client_name = os.getenv("OAUTH_APP_NAME")
client_id = os.getenv("OAUTH_APP_CLIENT_ID")
client_secret = os.getenv("OAUTH_APP_CLIENT_SECRET")
site = Site.objects.get(domain=os.getenv("LMS_HOST"))
app, created = Application.objects.update_or_create(
client_id=client_id,
defaults={
'client_secret': client_secret,
'client_type': Application.CLIENT_CONFIDENTIAL,
'authorization_grant_type': Application.GRANT_CLIENT_CREDENTIALS,
'name': client_name,
'skip_authorization': True
}
)
if created:
print(f"Created new OAuth app client: {client_name}")
else:
print(f"Updated existing OAuth app client: {client_name}")
def create_oauth_provider():
setup_django_environment()
from common.djangoapps.third_party_auth.models import OAuth2ProviderConfig
from django.contrib.sites.models import Site
provider_name = os.getenv("OAUTH_IDENTITY_PROVIDER_NAME")
client_id = os.getenv("OAUTH_IDENTITY_PROVIDER_ID")
client_secret = os.getenv("OAUTH_IDENTITY_PROVIDER_SECRET")
site = Site.objects.get(domain=os.getenv("LMS_HOST"))
provider, created = OAuth2ProviderConfig.objects.update_or_create(
name=provider_name,
defaults={
"enabled": True,
"client_id": client_id,
"client_secret": client_secret,
"icon_class": "fa-sign-in",
"skip_registration_form": True,
"site": site
}
)
if created:
print(f"Created new OAuth Provider: {provider_name}")
else:
print(f"Updated existing OAuth Provider: {provider_name}")
# Hook into Tutor's lifecycle for execution when Docker Compose projects start
@hooks.Actions.COMPOSE_PROJECT_STARTED.add()
def on_compose_project_start(root, config, name):
create_oauth_app_client()
create_oauth_provider()
Error applying action: func=<function on_compose_project_start at 0x101bff010> contexts=[‘plugins’, ‘app:oauth_client_provider_plugin’]’
Traceback (most recent call last):
File “/Users/ivorscott/Charite/interagent-tutor/.venv/bin/tutor”, line 8, in
sys.exit(main())
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/commands/cli.py”, line 27, in main
cli() # pylint: disable=no-value-for-parameter
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 1157, in call
return self.main(*args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 1078, in main
rv = self.invoke(ctx)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 1688, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 1688, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 783, in invoke
return __callback(*args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/decorators.py”, line 33, in new_func
return f(get_current_context(), *args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/commands/compose.py”, line 269, in reboot
context.invoke(start, detach=detach, services=services)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/core.py”, line 783, in invoke
return __callback(*args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/click/decorators.py”, line 45, in new_func
return f(get_current_context().obj, *args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/commands/compose.py”, line 249, in start
context.job_runner(config).docker_compose(*command, *services)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/commands/compose.py”, line 39, in docker_compose
hooks.Actions.COMPOSE_PROJECT_STARTED.do(
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/core/hooks/actions.py”, line 116, in do
self.do_from_context(None, *args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/core/hooks/actions.py”, line 135, in do_from_context
callback.do(
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/tutor/core/hooks/actions.py”, line 36, in do
self.func(*args, **kwargs)
File “/Users/ivorscott/Charite/interagent-tutor/tutor-plugins/oauth_client_provider_plugin.py”, line 65, in on_compose_project_start
create_oauth_app_client()
File “/Users/ivorscott/Charite/interagent-tutor/tutor-plugins/oauth_client_provider_plugin.py”, line 10, in create_oauth_app_client
setup_django_environment()
File “/Users/ivorscott/Charite/interagent-tutor/tutor-plugins/oauth_client_provider_plugin.py”, line 7, in setup_django_environment
django.setup()
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/django/init.py”, line 19, in setup
configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/django/conf/init.py”, line 81, in getattr
self._setup(name)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/django/conf/init.py”, line 68, in _setup
self._wrapped = Settings(settings_module)
File “/Users/ivorscott/Charite/interagent-tutor/.venv/lib/python3.10/site-packages/django/conf/init.py”, line 166, in init
mod = importlib.import_module(self.SETTINGS_MODULE)
File “/opt/homebrew/Cellar/python@3.10/3.10.14_1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/importlib/init.py”, line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File “”, line 1050, in _gcd_import
File “”, line 1027, in _find_and_load
File “”, line 992, in _find_and_load_unlocked
File “”, line 241, in _call_with_frames_removed
File “”, line 1050, in _gcd_import
File “”, line 1027, in _find_and_load
File “”, line 992, in _find_and_load_unlocked
File “”, line 241, in _call_with_frames_removed
File “”, line 1050, in _gcd_import
File “”, line 1027, in _find_and_load
File “”, line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named ‘lms’
I noticed manage.py in the lms already allows the creation of an OAuth client app (manage.py createapplication or manage.py create_dot_application). Maybe I need to make my own manage.py command for identity provider creation but I don’t know how.