Ghostwriter icon indicating copy to clipboard operation
Ghostwriter copied to clipboard

Documentation for SSO Implementation

Open joonhohw opened this issue 4 years ago • 5 comments

The press release for Ghostwriter indicates that SSO can be enabled for the application, but it is unclear how this can be implemented. Documentation of the process would be helpful, as we use a custom SSO implementation.

joonhohw avatar Oct 22 '20 18:10 joonhohw

FYI I did manage to enable OAuth with Azure AD this way:

diff --git a/config/settings/local.py b/config/settings/local.py
index fb423d5..839db1c 100644
--- a/config/settings/local.py
+++ b/config/settings/local.py
@@ -62,3 +62,21 @@ INSTALLED_APPS += ["django_extensions"]  # noqa F405

 # Your stuff...
 # ------------------------------------------------------------------------------
+INSTALLED_APPS += ["allauth.socialaccount.providers.azure"]
+SITE_ID = 1
+
+# Provider specific settings
+SOCIALACCOUNT_PROVIDERS = {
+    'azure': {
+        # For each OAuth based provider, either add a ``SocialApp``
+        # (``socialaccount`` app) containing the required client
+        # credentials, or list them here:
+        'APP': {
+            'client_id': '<<CLIENT_ID>>',
+            'secret': '<<CLIENT_SECRET>>',
+        }
+    }
+}
+ACCOUNT_AUTHENTICATION_METHOD = "email"
+ACCOUNT_EMAIL_REQUIRED = True

A side not is that the allauth module has hardcoded the login URL to https://login.microsoftonline.com/common/oauth2/v2.0 (https://github.com/pennersr/django-allauth/blob/cc0dfb7b30b22a8e68eaa35019515c5180e183f0/allauth/socialaccount/providers/azure/views.py#L14), which means you cannot force the authentication to a single tenant in Azure AD (multi-tenant needs to be selected).

image

fastlorenzo avatar Jul 20 '21 14:07 fastlorenzo

I tried to do the same for Google Auth. Everything works fine until I am redirected back and get a screen informing me that signup is disabled. Does this feature only work with account registration enabled?

er4z0r avatar Jul 27 '21 14:07 er4z0r

So for anyone out there trying to get this working with Google.

You will need to setup an OAuth Client App with the Google Developer Console. You can find a tutorial on allauth with Google here.

Here is what I used config/settings/production.py:

INSTALLED_APPS += ["allauth.socialaccount.providers.google"]

SITE_ID = 1

SOCIAL_AUTH_AUTHENTICATION_BACKENDS = "social_core.backends.google.GoogleOAuth2"
SOCIALACCOUNT_PROVIDERS = {
        'google': {
            'SCOPE': ['profile','email'],
            'AUTH_PARAMS': { 'access_type': 'online' }
        }
}

#SOCIALACCOUNT_ADAPTER="ghostwriter.users.adapters.OnlyExistingSocialAccountAdapter"

# Provider specific settings
SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ["yourdomain.com"]

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_ALLOW_REGISTRATION = False

Since I only wanted existing users with an e-mail address to be able to use the Google Login I had to create a new SocialAdapter. Add the following to your ghostwriter/users/adapters.py:

"""This contains the ``allauth`` adapters used by the Users application."""
  
# Standard Libraries
from typing import Any

# Django Imports
from django.conf import settings
from django.http import HttpRequest,HttpResponse

# 3rd Party Libraries
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.account.models import EmailAddress
from allauth.utils import get_user_model
from allauth.exceptions import ImmediateHttpResponse

class AccountAdapter(DefaultAccountAdapter):  # pragma: no cover
    def is_open_for_signup(self, request: HttpRequest):
        return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)


class SocialAccountAdapter(DefaultSocialAccountAdapter):  # pragma: no cover
    def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
        return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)

class OnlyExistingSocialAccountAdapter(SocialAccountAdapter):

    def pre_social_login(self, request, sociallogin):
        try:
            get_user_model().objects.get(email=sociallogin.user.email)
        except get_user_model().DoesNotExist:
            from django.contrib import messages
            messages.add_message(request, messages.ERROR, 'Social logon from this account not allowed.')
            raise ImmediateHttpResponse(HttpResponse(status=500))
        else:
            user = get_user_model().objects.get(email=sociallogin.user.email)
            if not sociallogin.is_existing:
                sociallogin.connect(request, user)

    def is_open_for_signup(self, request, sociallogin):
        return True

This code is not my creation but was copied from here.

If you want your Ghostwriter to behave the same, uncomment the line with SOCIALACCOUNT_ADAPTER in the config/settings.

er4z0r avatar Jul 15 '22 16:07 er4z0r

Thanks for sharing, @er4z0r! I'll see if this can be adapted for the wiki.

chrismaddalena avatar Jul 26 '22 15:07 chrismaddalena

FYI I did manage to enable OAuth with Azure AD this way:

diff --git a/config/settings/local.py b/config/settings/local.py
index fb423d5..839db1c 100644
--- a/config/settings/local.py
+++ b/config/settings/local.py
@@ -62,3 +62,21 @@ INSTALLED_APPS += ["django_extensions"]  # noqa F405

 # Your stuff...
 # ------------------------------------------------------------------------------
+INSTALLED_APPS += ["allauth.socialaccount.providers.azure"]
+SITE_ID = 1
+
+# Provider specific settings
+SOCIALACCOUNT_PROVIDERS = {
+    'azure': {
+        # For each OAuth based provider, either add a ``SocialApp``
+        # (``socialaccount`` app) containing the required client
+        # credentials, or list them here:
+        'APP': {
+            'client_id': '<<CLIENT_ID>>',
+            'secret': '<<CLIENT_SECRET>>',
+        }
+    }
+}
+ACCOUNT_AUTHENTICATION_METHOD = "email"
+ACCOUNT_EMAIL_REQUIRED = True

A side not is that the allauth module has hardcoded the login URL to https://login.microsoftonline.com/common/oauth2/v2.0 (https://github.com/pennersr/django-allauth/blob/cc0dfb7b30b22a8e68eaa35019515c5180e183f0/allauth/socialaccount/providers/azure/views.py#L14), which means you cannot force the authentication to a single tenant in Azure AD (multi-tenant needs to be selected).

image

Was able to get SSO with Azure AD working with single tenant. This is the step-by-step guide I have so far, open to suggestions.

Azure In Azure Portal, create a new App Registration:

  • Name: some identifiable name
  • Callback URL: https://ghostwriter.example.com/accounts/microsoft/login/callback/
  • Supported account types: Accounts in this organizational directory only (DIR only - Single tenant)

After creating the app, create a client secret in the App Registration:

  • Manage > Certificates & secrets > New client secret -- copy the 'Value', will need later in Django > Command Center > Social Application setup

Ghostwriter Add to end of: config/settings/production.py:

INSTALLED_APPS += ["allauth.socialaccount.providers.microsoft"]
SOCIALACCOUNT_PROVIDERS = {
   'microsoft': {
           'TENANT': '<Directory (tenant) ID>',
           'client_id': '<Application (client) ID>',
   }
}

^ note that TENANT is in all caps. This is required per: https://django-allauth.readthedocs.io/en/latest/release-notes.html#backwards-incompatible-changes

Add social registration to config, allowing users in the target tenant to register an account in GW: $ ./ghostwriter-cli config set DJANGO_SOCIAL_ACCOUNT_ALLOW_REGISTRATION true

Rebuild containers:

$ ./ghostwriter-cli containers down
$ ./ghostwriter-cli containers build
$ ./ghostwriter-cli containers up

Log back into the Ghostwriter app as admin, go to the Command Center.

Go to Sites > Add Site:

  • Domain name: domain name of ghostwriter server, e.g. ghostwriter.example.com
  • Display name: some identifiable name

SAVE

Go to Social applications, Add Social Application:

  • Provider: Microsoft Graph
  • Name: some identifiable name
  • Client id: Application (client) ID
  • Secret key: Value from App Registration client secret
  • Sites: select the ghostwriter site, move into Chosen Sites column

SAVE

porterhau5 avatar Apr 26 '23 17:04 porterhau5