py-mssso


Namepy-mssso JSON
Version 0.0.1 PyPI version JSON
download
home_pageNone
SummaryMS SSO Helper for Python
upload_time2024-10-29 17:03:27
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseThe MIT License (MIT) Copyright (c) 2024 Sungwon Um Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords azure sso msal
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Installation

Use pip:

```
pip install py-mssso
```
or

```
pip install git+https://github.com/shineum/py_mssso.git
```


# Prerequisites
Create Azure App with MS Azure Protal "App registrations".
These information from Azure App are required.
- Directory (tenant) ID (Overview)
- Application (client) ID (Overview)
- Client secret (Manage - Certificates & secrets)
- scopes (Manage - API permissions)
- redirect url (Manage - Authentication - Web Redirect URIs)


# Getting Started
```
from py_mssso import MSSSOHelper

...

MSSSOHelper.add(
    **{
        "tenant_type": MS_SSO_TENANT_TYPE,
        "tenant_id": MS_SSO_TENANT_ID,
        "client_id": MS_SSO_CLIENT_ID,
        "client_secret": MS_SSO_CLIENT_SECRET,
        "scopes": MS_SSO_SCOPES,
        "redirect_url": MS_SSO_REDIRECT_URL,
    }
)
```

#### tenant_type
```
"SINGLE", "MULTI" or "PUBLIC" - default: "SINGLE"
```

#### scopes
```
["User.Read"]: Read user data only for login user
["User.Read.All"]: when you need to read other user's information (ex: manager of login user)
```

#### redirect_url
```
url must be set in Web Redirect URIs in Azure App
```


# login url
django example
```
# view.py
from py_mssso import MSSSOHelper
from django.http import HttpResponseRedirect

...

# sso login
def sso_login(request):
    if not request.session.session_key:
        request.session.create()
    msal_flow = MSSSOHelper.get().get_auth_code_flow()
    request.session["msal_flow"] = msal_flow
    request.session.save()
    return HttpResponseRedirect(msal_flow.get("auth_uri"))
```


# callback url
django example
```
# view.py
import requests
from django.contrib.auth import get_user_model
from django.contrib.auth import login
from django.http import HttpResponseRedirect
from py_mssso import MSSSOHelper

_LOGIN_FAIL_URL = "/"
_LOGIN_SUCCESS_URL = "/"
_MSGRAPH_BASE_URI = "https://graph.microsoft.com/v1.0"
_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER = ",".join(
    [
        "displayName",
        "givenName",
        "surname",
        "mail",
        "mobilePhone",
        "officeLocation",
        "userPrincipalName",
        "jobTitle",
        "department",
        "companyName",
        "onPremisesSamAccountName",
    ]
)

...

# django login helper
def _login(request, username):
    try:
        user = get_user_model().objects.get(username=username)
        user.backend = "django.contrib.auth.backends.ModelBackend"
        login(request, user)
    except:
        raise Exception(f"Login Failed - user not exist: [{username}]")

# sso callback
def sso_login_callback(request):
    code = request.GET.get("code")
    state = request.GET.get("state")
    session_state = request.GET.get("session_state")
    msal_flow = request.session.get("msal_flow")

    try:
        # request validation
        if not code:
            raise Exception("Invalid request")

        # get token info
        token_info = MSSSOHelper.get().get_token_info(
            auth_code_flow=msal_flow,
            auth_res={
                "code": code,
                "state": state,
                "session_state": session_state,
            },
        )

        # token info validation
        if not token_info:
            raise Exception("Invalid request")

        # find token
        token = token_info.get("access_token")

        # token validation
        if not token:
            raise Exception("Invalid request")

        # set request header
        headers = {"Authorization": f"Bearer {token}"}

        # get user data with MS Graph API
        res_user = requests.get(
            f"{_MSGRAPH_BASE_URI}/me?$select={_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER}",
            headers=headers,
        )

        # get manager data with MS Graph API (Optional, "User.Read.All" permission is required)
        res_manager = requests.get(
            f"{_MSGRAPH_BASE_URI}/me/manager?$select={_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER}",
            headers=headers,
        )

        ##############################################
        # Run some processes with user / manager data
        # ex) create (django) user if not exist
        #     or update profile if necessary
        ##############################################

        # parse user object
        ms_user_obj = res_user.json()

        # set username - it could be "userPrincipalName", "onPremisesSamAccountName" or any other values depending on your settings
        username = ms_user_obj.get("userPrincipalName")
        if not username:
            raise Exception("Invalid User")

        # create or update django user
        get_user_model().objects.update_or_create(
            username=username,
            defaults={
                "first_name": ms_user_obj.get("givenName"),
                "last_name": ms_user_obj.get("surname"),
                "email": ms_user_obj.get("mail"),
                "is_active": True,
            },
        )

        # django login
        _login(request, username)
    except:
        return HttpResponseRedirect(_LOGIN_FAIL_URL)

    return HttpResponseRedirect(_LOGIN_SUCCESS_URL)
```

# sample project
```
https://github.com/shineum/py_mssso_sample
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "py-mssso",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "azure, sso, msal",
    "author": null,
    "author_email": "Sungwon Um <shineum@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/c6/cc/4a9c6754ec59c663e87aa1fa2d06321ea467cb68b8a3449f555688fc7541/py_mssso-0.0.1.tar.gz",
    "platform": null,
    "description": "# Installation\r\n\r\nUse pip:\r\n\r\n```\r\npip install py-mssso\r\n```\r\nor\r\n\r\n```\r\npip install git+https://github.com/shineum/py_mssso.git\r\n```\r\n\r\n\r\n# Prerequisites\r\nCreate Azure App with MS Azure Protal \"App registrations\".\r\nThese information from Azure App are required.\r\n- Directory (tenant) ID (Overview)\r\n- Application (client) ID (Overview)\r\n- Client secret (Manage - Certificates & secrets)\r\n- scopes (Manage - API permissions)\r\n- redirect url (Manage - Authentication - Web Redirect URIs)\r\n\r\n\r\n# Getting Started\r\n```\r\nfrom py_mssso import MSSSOHelper\r\n\r\n...\r\n\r\nMSSSOHelper.add(\r\n    **{\r\n        \"tenant_type\": MS_SSO_TENANT_TYPE,\r\n        \"tenant_id\": MS_SSO_TENANT_ID,\r\n        \"client_id\": MS_SSO_CLIENT_ID,\r\n        \"client_secret\": MS_SSO_CLIENT_SECRET,\r\n        \"scopes\": MS_SSO_SCOPES,\r\n        \"redirect_url\": MS_SSO_REDIRECT_URL,\r\n    }\r\n)\r\n```\r\n\r\n#### tenant_type\r\n```\r\n\"SINGLE\", \"MULTI\" or \"PUBLIC\" - default: \"SINGLE\"\r\n```\r\n\r\n#### scopes\r\n```\r\n[\"User.Read\"]: Read user data only for login user\r\n[\"User.Read.All\"]: when you need to read other user's information (ex: manager of login user)\r\n```\r\n\r\n#### redirect_url\r\n```\r\nurl must be set in Web Redirect URIs in Azure App\r\n```\r\n\r\n\r\n# login url\r\ndjango example\r\n```\r\n# view.py\r\nfrom py_mssso import MSSSOHelper\r\nfrom django.http import HttpResponseRedirect\r\n\r\n...\r\n\r\n# sso login\r\ndef sso_login(request):\r\n    if not request.session.session_key:\r\n        request.session.create()\r\n    msal_flow = MSSSOHelper.get().get_auth_code_flow()\r\n    request.session[\"msal_flow\"] = msal_flow\r\n    request.session.save()\r\n    return HttpResponseRedirect(msal_flow.get(\"auth_uri\"))\r\n```\r\n\r\n\r\n# callback url\r\ndjango example\r\n```\r\n# view.py\r\nimport requests\r\nfrom django.contrib.auth import get_user_model\r\nfrom django.contrib.auth import login\r\nfrom django.http import HttpResponseRedirect\r\nfrom py_mssso import MSSSOHelper\r\n\r\n_LOGIN_FAIL_URL = \"/\"\r\n_LOGIN_SUCCESS_URL = \"/\"\r\n_MSGRAPH_BASE_URI = \"https://graph.microsoft.com/v1.0\"\r\n_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER = \",\".join(\r\n    [\r\n        \"displayName\",\r\n        \"givenName\",\r\n        \"surname\",\r\n        \"mail\",\r\n        \"mobilePhone\",\r\n        \"officeLocation\",\r\n        \"userPrincipalName\",\r\n        \"jobTitle\",\r\n        \"department\",\r\n        \"companyName\",\r\n        \"onPremisesSamAccountName\",\r\n    ]\r\n)\r\n\r\n...\r\n\r\n# django login helper\r\ndef _login(request, username):\r\n    try:\r\n        user = get_user_model().objects.get(username=username)\r\n        user.backend = \"django.contrib.auth.backends.ModelBackend\"\r\n        login(request, user)\r\n    except:\r\n        raise Exception(f\"Login Failed - user not exist: [{username}]\")\r\n\r\n# sso callback\r\ndef sso_login_callback(request):\r\n    code = request.GET.get(\"code\")\r\n    state = request.GET.get(\"state\")\r\n    session_state = request.GET.get(\"session_state\")\r\n    msal_flow = request.session.get(\"msal_flow\")\r\n\r\n    try:\r\n        # request validation\r\n        if not code:\r\n            raise Exception(\"Invalid request\")\r\n\r\n        # get token info\r\n        token_info = MSSSOHelper.get().get_token_info(\r\n            auth_code_flow=msal_flow,\r\n            auth_res={\r\n                \"code\": code,\r\n                \"state\": state,\r\n                \"session_state\": session_state,\r\n            },\r\n        )\r\n\r\n        # token info validation\r\n        if not token_info:\r\n            raise Exception(\"Invalid request\")\r\n\r\n        # find token\r\n        token = token_info.get(\"access_token\")\r\n\r\n        # token validation\r\n        if not token:\r\n            raise Exception(\"Invalid request\")\r\n\r\n        # set request header\r\n        headers = {\"Authorization\": f\"Bearer {token}\"}\r\n\r\n        # get user data with MS Graph API\r\n        res_user = requests.get(\r\n            f\"{_MSGRAPH_BASE_URI}/me?$select={_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER}\",\r\n            headers=headers,\r\n        )\r\n\r\n        # get manager data with MS Graph API (Optional, \"User.Read.All\" permission is required)\r\n        res_manager = requests.get(\r\n            f\"{_MSGRAPH_BASE_URI}/me/manager?$select={_MSGRAPH_QUERY_SELECT_ITEMS_FOR_USER}\",\r\n            headers=headers,\r\n        )\r\n\r\n        ##############################################\r\n        # Run some processes with user / manager data\r\n        # ex) create (django) user if not exist\r\n        #     or update profile if necessary\r\n        ##############################################\r\n\r\n        # parse user object\r\n        ms_user_obj = res_user.json()\r\n\r\n        # set username - it could be \"userPrincipalName\", \"onPremisesSamAccountName\" or any other values depending on your settings\r\n        username = ms_user_obj.get(\"userPrincipalName\")\r\n        if not username:\r\n            raise Exception(\"Invalid User\")\r\n\r\n        # create or update django user\r\n        get_user_model().objects.update_or_create(\r\n            username=username,\r\n            defaults={\r\n                \"first_name\": ms_user_obj.get(\"givenName\"),\r\n                \"last_name\": ms_user_obj.get(\"surname\"),\r\n                \"email\": ms_user_obj.get(\"mail\"),\r\n                \"is_active\": True,\r\n            },\r\n        )\r\n\r\n        # django login\r\n        _login(request, username)\r\n    except:\r\n        return HttpResponseRedirect(_LOGIN_FAIL_URL)\r\n\r\n    return HttpResponseRedirect(_LOGIN_SUCCESS_URL)\r\n```\r\n\r\n# sample project\r\n```\r\nhttps://github.com/shineum/py_mssso_sample\r\n```\r\n",
    "bugtrack_url": null,
    "license": "The MIT License (MIT)  Copyright (c) 2024 Sungwon Um  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
    "summary": "MS SSO Helper for Python",
    "version": "0.0.1",
    "project_urls": {
        "Homepage": "https://github.com/shineum/py_mssso"
    },
    "split_keywords": [
        "azure",
        " sso",
        " msal"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2284bd8b7402b2ffbfa0404c2be4b114bbbd31b12cb6a9a8e14d3087cb270128",
                "md5": "ec9524aecdddaa1378d4cfc49b8d78a8",
                "sha256": "97ab01099485dba3bdc3ede76f413c92a2dda259eaf6dad5f67ff721f2bce9f5"
            },
            "downloads": -1,
            "filename": "py_mssso-0.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ec9524aecdddaa1378d4cfc49b8d78a8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 5426,
            "upload_time": "2024-10-29T17:03:25",
            "upload_time_iso_8601": "2024-10-29T17:03:25.732206Z",
            "url": "https://files.pythonhosted.org/packages/22/84/bd8b7402b2ffbfa0404c2be4b114bbbd31b12cb6a9a8e14d3087cb270128/py_mssso-0.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c6cc4a9c6754ec59c663e87aa1fa2d06321ea467cb68b8a3449f555688fc7541",
                "md5": "bb0ad77622db4c35ef1b42c38ce09b4a",
                "sha256": "9ff261ed74dd5af06e50c97aabaa5e9143ab86268950ec939b774b9a7edd3848"
            },
            "downloads": -1,
            "filename": "py_mssso-0.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "bb0ad77622db4c35ef1b42c38ce09b4a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 4722,
            "upload_time": "2024-10-29T17:03:27",
            "upload_time_iso_8601": "2024-10-29T17:03:27.240567Z",
            "url": "https://files.pythonhosted.org/packages/c6/cc/4a9c6754ec59c663e87aa1fa2d06321ea467cb68b8a3449f555688fc7541/py_mssso-0.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-29 17:03:27",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "shineum",
    "github_project": "py_mssso",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "py-mssso"
}
        
Elapsed time: 1.74181s