# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/routes/sso.ipynb.

# %% auto 0
__all__ = ['SSO_AddUserDirectSignonError', 'toggle_user_direct_signon_access', 'SSO_GET_Error', 'SSO_CRUD_Error',
           'get_sso_oidc_config', 'generate_sso_oidc_body', 'update_sso_oidc_config', 'get_sso_saml_config',
           'get_sso_saml_certificate', 'generate_sso_saml_body', 'update_sso_saml_config', 'toggle_sso_skip_to_idp',
           'toggle_sso_custom_attributes', 'set_sso_certificate']

# %% ../../nbs/routes/sso.ipynb 2
import httpx

from typing import List

import domolibrary.client.get_data as gd
import domolibrary.client.ResponseGetData as rgd
import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoError as de

from domolibrary.utils.convert import convert_string_to_bool


# %% ../../nbs/routes/sso.ipynb 6
class SSO_AddUserDirectSignonError(de.DomoError):
    def __init__(self,
                 res : rgd.ResponseGetData ,
                 user_id_ls : List[str],
                 message= None):
        
        message = message or f"unable to add {', '.join(user_id_ls)} to DSO {res.response}"
        super().__init__(status= res.status,
                         domo_instance=res.auth.domo_instance,
                         message= message )
        
@gd.route_function
async def toggle_user_direct_signon_access(
    auth: dmda.DomoAuth,
    user_id_ls: List[str],
    is_enable_direct_signon : bool = True,
    
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class=None,
    debug_num_stacks_to_drop=1,
) -> rgd.ResponseGetData:

    user_id_ls = user_id_ls if isinstance(user_id_ls, list) else [user_id_ls]
    
    url = f"https://{auth.domo_instance}.domo.com/api/content/v3/users/directSignOn"
    
    res = await gd.get_data(
        auth=auth,
        url=url,
        params = { "value" : is_enable_direct_signon},
        method="POST",
        body = user_id_ls,
        session=session,
        debug_api=debug_api,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    if not res.is_success:
        raise SSO_AddUserDirectSignonError(
            res = res,
            user_id_ls = user_id_ls
        )
        
    res.response = f"successfully added {', '.join(user_id_ls)} to direct signon list in {auth.domo_instance}"
        
    return res

# %% ../../nbs/routes/sso.ipynb 9
class SSO_GET_Error(de.DomoError):    
    def __init__(self,
                 res : rgd.ResponseGetData ,
                 message= None):
        
        message = message or f"unable to rerieve SSO Config for {res.auth.domo_instance} - {res.response}"
        super().__init__(status= res.status,
                         domo_instance=res.auth.domo_instance,
                         message= message )
        

class SSO_CRUD_Error(de.DomoError):    
    def __init__(self,
                 res : rgd.ResponseGetData ,
                 message= None):
        
        message = message or f"unable to update SSO Config for {res.auth.domo_instance} - {res.response}"
        super().__init__(status= res.status,
                         domo_instance=res.auth.domo_instance,
                         message= message )   

# %% ../../nbs/routes/sso.ipynb 11
@gd.route_function
async def get_sso_oidc_config(
    auth: dmda.DomoAuth,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    """Open ID Connect framework"""

    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/oidc/std/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise SSO_GET_Error(
            res = res
        )
    
    return res



# %% ../../nbs/routes/sso.ipynb 14
class SSO_CRUD_Error(de.DomoError):
    def __init__(self, res: rgd.ResponseGetData, message=None):

        message = (
            message
            or f"unable to update SSO Config for {res.auth.domo_instance} - {res.response}"
        )
        super().__init__(
            status=res.status, domo_instance=res.auth.domo_instance, message=message
        )


def generate_sso_oidc_body(
    is_include_undefined: bool = False,

    login_enabled: bool = None,  # False
    idp_enabled: bool = None,  # False
    import_groups: bool = None,  # False
    require_invitation: bool = None,  # False
    enforce_allowlist: bool = None,  # False
    skip_to_idp: bool = None,  # False
    auth_request_endpoint: str = None,
    token_endpoint: str = None,
    user_info_endpoint: str = None,
    public_key: str = None,
    redirect_url: str = None,
    idp_certificate: str = None,
    override_sso: bool = None,  # False
    override_embed: bool = None,  # False
    # "https://{domo_instance}}.domo.com/auth/oidc"
    well_known_config: str = None,
    assertion_endpoint: str = None,
    ingest_attributes: bool = None,  # False
):
    r = {
        "loginEnabled": login_enabled,
        "idpEnabled": idp_enabled,
        "importGroups": import_groups,
        "requireInvitation": require_invitation,
        "enforceWhitelist": enforce_allowlist,
        "skipToIdp": skip_to_idp,
        "authRequestEndpoint": auth_request_endpoint,
        "tokenEndpoint": token_endpoint,
        "userInfoEndpoint": user_info_endpoint,
        "publicKey": public_key,
        "redirectUrl": redirect_url,
        "certificate": idp_certificate,
        "overrideSSO": override_sso,
        "overrideEmbed": override_embed,
        "wellKnownConfig": well_known_config,
        "assertionEndpoint": assertion_endpoint,
        "ingestAttributes": ingest_attributes,
    }

    if not is_include_undefined:
        return {key: value for key, value in r.items() if value is not None}

    return r

# %% ../../nbs/routes/sso.ipynb 15
@gd.route_function
async def _update_sso_oidc_temp_config(
    auth: dmda.DomoAuth,
    body_sso: dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    """to successfully update the SSO Configuration, you must send all the parameters related to SSO Configuration"""
    
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/oidc/temp/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        body=body_sso,
        method="PUT",
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise SSO_CRUD_Error(
            res = res
        )
    return res

@gd.route_function
async def _update_sso_oidc_standard_config(
    auth: dmda.DomoAuth,
    body_sso: dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    """to successfully update the SSO Configuration, you must send all the parameters related to SSO Configuration"""
    
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/oidc/std/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        body=body_sso,
        method="PUT",
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise SSO_CRUD_Error(
            res = res
        )
    
    if body_sso.get('idpEnabled') == False:
        res.response = 'successfully disabled SSO'
        return res
    
    res.response = 'successfully updated oidc config'

    return res

@gd.route_function
async def update_sso_oidc_config(
    auth: dmda.DomoAuth,
    body_sso: dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    
    """
    to update saml config must update temp and then standard
    typically would hide under class functions, but b/c Domo won't update w/o it, pushing down to Route
    """
    
    await _update_sso_oidc_temp_config(
        auth = auth,
        body_sso = body_sso,
        session = session,
        debug_api = debug_api,
        parent_class = parent_class,
        debug_num_stacks_to_drop= debug_num_stacks_to_drop + 1
    )
    
    
    return await _update_sso_oidc_standard_config(
        auth = auth,
        body_sso = body_sso,
        session = session,
        debug_api = debug_api,
        parent_class = parent_class,
        debug_num_stacks_to_drop= debug_num_stacks_to_drop + 1,
    )

# %% ../../nbs/routes/sso.ipynb 18
@gd.route_function
async def get_sso_saml_config(
    auth: dmda.DomoAuth,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    """Security Assertion Markup Language"""

    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/saml/std/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if not res.is_success:
        raise SSO_GET_Error(res = res)
    
    return res


# %% ../../nbs/routes/sso.ipynb 20
@gd.route_function
async def get_sso_saml_certificate(
    auth: dmda.DomoAuth,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):

    res = await get_sso_saml_config(auth = auth,
                                    session = session,
                                    debug_api = debug_api,
                                    parent_class= parent_class,
                                    debug_num_stacks_to_drop =debug_num_stacks_to_drop+1
                                   )
    
    res.response = res.response.get('idpCertificate')
    
    return res

# %% ../../nbs/routes/sso.ipynb 23
def generate_sso_saml_body(
    is_include_undefined: bool = False, # leave it as False to prevent overriding values you don't want to update

    is_enabled : bool = None,
    auth_request_endpoint : str = None, # url
    issuer: str = None, #url
    idp_certificate : str = None,
    import_groups : bool = None,
    require_invitation : bool = None,
    enforce_allowlist : bool = None,
    relay_state :bool = None,
    redirect_url : str = None, # url
    idp_enabled : bool = None,
    skip_to_idp : bool = None,
    
    login_enabled = None,
    token_endpoint = None,
    user_info_endpoint = None,
    public_key = None,
    override_sso = None,
    override_embed =None,
    well_known_config = None,
    assertion_endpoint = None,
    ingest_attributes = None,
    custom_attributes = None,
):
    if skip_to_idp is not None:
        skip_to_idp = str(skip_to_idp).lower()
    
    r = {
        "enabled" : is_enabled,
        "authRequestEndpoint": auth_request_endpoint,
        "issuer" : issuer,
        "idpCertificate": idp_certificate,
        "importGroups": import_groups,
        "requireInvitation": require_invitation,
        "enforceWhitelist": enforce_allowlist,
        "relayState" : relay_state,
        "idpEnabled": idp_enabled,
        "skipToIdp": skip_to_idp,
        "customAttributes" : custom_attributes,
        
        "loginEnabled": login_enabled,
        "tokenEndpoint": token_endpoint,
        "userInfoEndpoint": user_info_endpoint,
        "publicKey": public_key,
        "redirectUrl": redirect_url,
        "overrideSSO": override_sso,
        "overrideEmbed": override_embed,
        "wellKnownConfig": well_known_config,
        "assertionEndpoint": assertion_endpoint,
        "ingestAttributes": ingest_attributes,
    }

    if not is_include_undefined:
        return {key: value for key, value in r.items() if value is not None}

    return r

# %% ../../nbs/routes/sso.ipynb 25
@gd.route_function
async def _update_sso_saml_temp_config(
    auth: dmda.DomoAuth,
    body_sso : dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/saml/temp/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=body_sso,
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if not res.is_success:
        raise SSO_CRUD_Error(res = res)
    
    res.response = 'successfully updated temp saml config'
    return res

@gd.route_function
async def _update_sso_saml_standard_config(
    auth: dmda.DomoAuth,
    body_sso : dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/saml/std/settings"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=body_sso,
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if not res.is_success:
        raise SSO_CRUD_Error(res = res)
        
    if body_sso.get('enabled') == False:
        res.response = 'successfully disabled SSO'
        return res
    
    res.response = 'successfully updated saml config'

    return res

# %% ../../nbs/routes/sso.ipynb 26
@gd.route_function
async def update_sso_saml_config(
    auth: dmda.DomoAuth,
    body_sso : dict,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    
    """
    to update saml config must update temp and then standard
    typically would hide under class functions, but b/c Domo won't update w/o it, pushing down to Route
    """

    await _update_sso_saml_temp_config(
        auth = auth,
        body_sso = body_sso,
        session = session,
        debug_api = debug_api,
        parent_class = parent_class,
        debug_num_stacks_to_drop= debug_num_stacks_to_drop + 1
    )
    
    
    return await _update_sso_saml_standard_config(
        auth = auth,
        body_sso = body_sso,
        session = session,
        debug_api = debug_api,
        parent_class = parent_class,
        debug_num_stacks_to_drop= debug_num_stacks_to_drop + 1,
    )

# %% ../../nbs/routes/sso.ipynb 29
@gd.route_function
async def toggle_sso_skip_to_idp(
    auth: dmda.DomoAuth,
    is_skip_to_idp : bool,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    url = f"https://{auth.domo_instance}.domo.com/api/customer/v1/properties/domo.policy.sso.skip_to_idp"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body={"value": str(is_skip_to_idp).lower()},
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if not res.is_success:
        raise SSO_CRUD_Error(res = res)
    
    res.response = f"toggled skip_to_idp - {str(is_skip_to_idp)}"
    return res

@gd.route_function
async def toggle_sso_custom_attributes(
    auth: dmda.DomoAuth,
    is_custom_attributes : bool,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
):
    """unsure what this API does"""
    
    url = f"https://{auth.domo_instance}.domo.com/api/customer/v1/properties/authentication.saml.custom_attributes"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body={"value": is_custom_attributes},
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if not res.is_success:
        raise SSO_CRUD_Error(res = res)
        
    res.response = f"toggled is_custom_attributes - {str(is_custom_attributes)}"

    
    return res

@gd.route_function
async def set_sso_certificate(
    auth: dmda.DomoAuth,
    idp_certificate : str,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
    return_raw: bool = False 
):
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/saml/validate/cert"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body={"idpCertificate": idp_certificate},
        session=session,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )
    
    if return_raw:
        return res
    
    if not res.is_success:
        raise SSO_CRUD_Error(res = res, message = f"API Error {res.response}")

    if not res.response['isValid']:
        raise SSO_CRUD_Error(res = res, message = f"Certificate Error: {res.response['message']}")

    return res
