# Path: invenio_oauthclient/contrib/keycloak/helpers.py
# def _format_public_key(public_key):
#     """PEM-format the public key."""
#     public_key = public_key.strip()
# 
#     if not public_key.startswith("-----BEGIN PUBLIC KEY-----"):
#         public_key = "-----BEGIN PUBLIC KEY-----\n" + \
#                      public_key + \
#                      "\n-----END PUBLIC KEY-----"
# 
#     return public_key
# 
# def get_user_info(remote, resp_token,
#                   fallback_to_endpoint=True,
#                   options=dict()):
#     """Get the user information from Keycloak.
# 
#     :param remote: The OAuthClient remote app
#     :param resp: The response from the 'token' endpoint; expected to be a dict
#         and to contain a JWT 'id_token'
#     :param fallback_to_endpoint: Whether or not to fall back to the 'userinfo'
#         endpoint mechanism when verifying the 'id_token' fails
#     :param options: A dictionary with additional options for `jwt.decode`
#     """
#     config_prefix = _generate_config_prefix(remote)
#     try:
#         # try to parse the "id_token" part of Keycloak's (JWT) response
#         token = resp_token["id_token"]
#         realm_url = current_app.config[f"{config_prefix}_REALM_URL"]
#         pubkey = _format_public_key(get_public_key(remote, realm_url))
#         alg = jwt.get_unverified_header(token)["alg"]
# 
#         if not isinstance(options, dict):
#             options = {}
# 
#         # consult the config whether to check the target audience
#         should_verify_aud = current_app.config.get(
#             f"{config_prefix}_VERIFY_AUD",
#             False
#         )
#         expected_aud = current_app.config.get(
#             f"{config_prefix}_AUD",
#             None
#         )
# 
#         if should_verify_aud and (expected_aud is not None):
#             options.update({"verify_aud": True})
#         else:
#             options.update({"verify_aud": False})
# 
#         # consult the config whether to check signature expiration
#         should_verify_expiration = current_app.config.get(
#             f"{config_prefix}_VERIFY_EXP",
#             False
#         )
# 
#         if should_verify_expiration:
#             options.update({"verify_exp": True})
#         else:
#             options.update({"verify_exp": False})
# 
#         user_info = jwt.decode(token,
#                                key=pubkey,
#                                algorithms=[alg],
#                                audience=expected_aud,
#                                options=options)
# 
#     except Exception as e:
#         if not fallback_to_endpoint:
#             raise OAuthKeycloakUserInfoError(
#                 "Error while fetching user information: {}".format(e),
#                 remote,
#                 resp_token
#             )
# 
#         # as a fallback, we can still contact Keycloak's userinfo endpoint
#         # `remote.get(...)` automatically includes OAuth2 tokens in the header
#         # and the response's `data` field is a dict
#         url = current_app.config[f"{config_prefix}_USER_INFO_URL"]
#         user_info = remote.get(url).data
# 
#     return user_info
# 
# Path: invenio_oauthclient/errors.py
# class OAuthError(Exception):
#     """Base class for OAuth exceptions."""
# 
#     def __init__(self, message, remote):
#         """Initialize exception.
# 
#         :param message: Error message.
#         :param message: Remote application.
#         """
#         self.message = message
#         self.remote = remote


import httpretty
import jwt
import pytest
from flask import session, url_for
from flask_login import current_user, login_user
from flask_security.utils import hash_password
from helpers import get_state, mock_keycloak
from invenio_accounts.models import User
from invenio_db import db
from six.moves.urllib_parse import parse_qs, urlparse
from invenio_oauthclient.contrib.keycloak.helpers import _format_public_key, \
    get_user_info
from invenio_oauthclient.errors import OAuthError
from invenio_oauthclient.models import UserIdentity
    with app.test_client() as c:
        assert not current_user.is_authenticated
        resp = c.get(
            url_for('invenio_oauthclient.disconnect', remote_app='keycloak')
        )
        assert resp.status_code == 302

# - - - - - - - - - - - - - - - - - - #
# Tests for Keycloak helper functions #
# - - - - - - - - - - - - - - - - - - #


def test_format_public_key(example_keycloak_public_key):
    """Test if _format_public_key does roughly the right thing."""
    fmt_key = _format_public_key(example_keycloak_public_key)

    assert fmt_key != example_keycloak_public_key
    assert example_keycloak_public_key in fmt_key
    assert fmt_key.startswith("-----BEGIN PUBLIC KEY-----\n")
    assert fmt_key.endswith("\n-----END PUBLIC KEY-----")

    strip_key = fmt_key.lstrip("-----BEGIN PUBLIC KEY-----")
    strip_key = strip_key.rstrip("-----END PUBLIC KEY-----")
    strip_key = strip_key.strip()

    assert example_keycloak_public_key == strip_key


def test_format_public_key_idempotence(example_keycloak_public_key):
    """Test whether the _format_public_key function is idempotent."""

# Path: invenio_oauthclient/contrib/keycloak/helpers.py
# def _format_public_key(public_key):
#     """PEM-format the public key."""
#     public_key = public_key.strip()
# 
#     if not public_key.startswith("-----BEGIN PUBLIC KEY-----"):
#         public_key = "-----BEGIN PUBLIC KEY-----\n" + \
#                      public_key + \
#                      "\n-----END PUBLIC KEY-----"
# 
#     return public_key
# 
# def get_user_info(remote, resp_token,
#                   fallback_to_endpoint=True,
#                   options=dict()):
#     """Get the user information from Keycloak.
# 
#     :param remote: The OAuthClient remote app
#     :param resp: The response from the 'token' endpoint; expected to be a dict
#         and to contain a JWT 'id_token'
#     :param fallback_to_endpoint: Whether or not to fall back to the 'userinfo'
#         endpoint mechanism when verifying the 'id_token' fails
#     :param options: A dictionary with additional options for `jwt.decode`
#     """
#     config_prefix = _generate_config_prefix(remote)
#     try:
#         # try to parse the "id_token" part of Keycloak's (JWT) response
#         token = resp_token["id_token"]
#         realm_url = current_app.config[f"{config_prefix}_REALM_URL"]
#         pubkey = _format_public_key(get_public_key(remote, realm_url))
#         alg = jwt.get_unverified_header(token)["alg"]
# 
#         if not isinstance(options, dict):
#             options = {}
# 
#         # consult the config whether to check the target audience
#         should_verify_aud = current_app.config.get(
#             f"{config_prefix}_VERIFY_AUD",
#             False
#         )
#         expected_aud = current_app.config.get(
#             f"{config_prefix}_AUD",
#             None
#         )
# 
#         if should_verify_aud and (expected_aud is not None):
#             options.update({"verify_aud": True})
#         else:
#             options.update({"verify_aud": False})
# 
#         # consult the config whether to check signature expiration
#         should_verify_expiration = current_app.config.get(
#             f"{config_prefix}_VERIFY_EXP",
#             False
#         )
# 
#         if should_verify_expiration:
#             options.update({"verify_exp": True})
#         else:
#             options.update({"verify_exp": False})
# 
#         user_info = jwt.decode(token,
#                                key=pubkey,
#                                algorithms=[alg],
#                                audience=expected_aud,
#                                options=options)
# 
#     except Exception as e:
#         if not fallback_to_endpoint:
#             raise OAuthKeycloakUserInfoError(
#                 "Error while fetching user information: {}".format(e),
#                 remote,
#                 resp_token
#             )
# 
#         # as a fallback, we can still contact Keycloak's userinfo endpoint
#         # `remote.get(...)` automatically includes OAuth2 tokens in the header
#         # and the response's `data` field is a dict
#         url = current_app.config[f"{config_prefix}_USER_INFO_URL"]
#         user_info = remote.get(url).data
# 
#     return user_info
# 
# Path: invenio_oauthclient/errors.py
# class OAuthError(Exception):
#     """Base class for OAuth exceptions."""
# 
#     def __init__(self, message, remote):
#         """Initialize exception.
# 
#         :param message: Error message.
#         :param message: Remote application.
#         """
#         self.message = message
#         self.remote = remote


# Path: tests/test_contrib_keycloak.py
import httpretty
import jwt
import pytest
from flask import session, url_for
from flask_login import current_user, login_user
from flask_security.utils import hash_password
from helpers import get_state, mock_keycloak
from invenio_accounts.models import User
from invenio_db import db
from six.moves.urllib_parse import parse_qs, urlparse
from invenio_oauthclient.contrib.keycloak.helpers import _format_public_key, \
    get_user_info
from invenio_oauthclient.errors import OAuthError
from invenio_oauthclient.models import UserIdentity

    with app.test_client() as c:
        assert not current_user.is_authenticated
        resp = c.get(
            url_for('invenio_oauthclient.disconnect', remote_app='keycloak')
        )
        assert resp.status_code == 302

# - - - - - - - - - - - - - - - - - - #
# Tests for Keycloak helper functions #
# - - - - - - - - - - - - - - - - - - #


def test_format_public_key(example_keycloak_public_key):
    """Test if _format_public_key does roughly the right thing."""
    fmt_key = _format_public_key(example_keycloak_public_key)

    assert fmt_key != example_keycloak_public_key
    assert example_keycloak_public_key in fmt_key
    assert fmt_key.startswith("-----BEGIN PUBLIC KEY-----\n")
    assert fmt_key.endswith("\n-----END PUBLIC KEY-----")

    strip_key = fmt_key.lstrip("-----BEGIN PUBLIC KEY-----")
    strip_key = strip_key.rstrip("-----END PUBLIC KEY-----")
    strip_key = strip_key.strip()

    assert example_keycloak_public_key == strip_key


def test_format_public_key_idempotence(example_keycloak_public_key):
    """Test whether the _format_public_key function is idempotent."""

    fmt_once = _format_public_key(example_keycloak_public_key)