Skip to content

Commit

Permalink
Merge pull request #272 from italia/dev
Browse files Browse the repository at this point in the history
Refresh Token, custom entities with policy loader, trust marked endpoint
  • Loading branch information
Giuseppe De Marco authored Sep 13, 2023
2 parents f66d318 + 8d7be4c commit a5855da
Show file tree
Hide file tree
Showing 32 changed files with 413 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ OIDCFED_DEFAULT_TRUST_ANCHOR = "http://127.0.0.1:8000"

OIDCFED_TRUST_ANCHORS = [OIDCFED_DEFAULT_TRUST_ANCHOR]

OIDCFED_PROVIDER_PROFILE = "spid"
OIDCFED_PROVIDER_MAX_REFRESH = 10 #used in SPID

# OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME = 3600 #used in CIE (seconds)

# for RP only
OIDCFED_IDENTITY_PROVIDERS = {
"spid": {
Expand Down
6 changes: 4 additions & 2 deletions examples/provider/provider/settingslocal.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ APPEND_SLASH = False
# required for onboarding checks and also for all the leafs
OIDCFED_DEFAULT_TRUST_ANCHOR = "http://127.0.0.1:8000"
OIDCFED_TRUST_ANCHORS = [OIDCFED_DEFAULT_TRUST_ANCHOR]
OIDCFED_PROVIDER_PROFILE = "cie"

OIDCFED_PROVIDER_PROFILE = "spid"
#OIDCFED_PROVIDER_MAX_REFRESH = 10 #used in SPID
OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME = 3600 #used in CIE (seconds)

OIDCFED_REQUIRED_TRUST_MARKS = []

#OIDCFED_FEDERATION_TRUST_MARKS_PROFILES = {
Expand Down
17 changes: 0 additions & 17 deletions examples/wallet_trust_anchor/templates/onboarding_landing.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,6 @@
<div class="d-lg-flex">
<div class="col-12">
<div class="row">
<div class="card-wrapper card-space col-6">
<div class="card card-bg no-after">
<div class="card-body pl-lg-0">
<div class="h-100">
<div class="col-12">
<div class="img-responsive-wrapper d-none d-lg-block h-100">
<div class="img-responsive img-responsive-panoramic h-100 ml-4 mt-2">
<figure class="img-wrapper">
<img alt="superman" class="h-100" src="{% static 'images/SPID-e-CIE-696x383.jpg' %}" title="spid-cie">
</figure>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-wrapper card-space col-6">
<div class="card card-bg no-after">
<div class="card-body pl-lg-0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ OIDCFED_FEDERATION_TRUST_MARKS_PROFILES = {
}

HTTPC_PARAMS = {
"connection": {"ssl": True},
"session": {"timeout": aiohttp.ClientTimeout(total=4)},
# enable/disable the connection params to avoid "Failed to fetch Entity Configuration -> ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:997)')]
# see: https://docs.aiohttp.org/en/v3.7.3/client_reference.html
# "connection": {"ssl": True, "verify_ssl": False},
"session": {
"timeout": aiohttp.ClientTimeout(total=4),
},
}

FEDERATION_DEFAULT_POLICY = {
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.0"
__version__ = "1.1.0"
2 changes: 1 addition & 1 deletion spid_cie_oidc/authority/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class FederationDescendantAdmin(admin.ModelAdmin):
readonly_fields = (
"created",
"modified",
"entity_statement_as_json",
"entity_statement_preview",
)
inlines = (
FederationDescendantContactAdminInline,
Expand Down
9 changes: 6 additions & 3 deletions spid_cie_oidc/authority/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def entity_profiles(self):
def entity_statement_as_dict(self, iss: str = None, aud: list = None) -> dict:

policies = {
k: FEDERATION_DEFAULT_POLICY[k] for k in self.entity_profiles
k: FEDERATION_DEFAULT_POLICY.get(k, {}) for k in self.entity_profiles
}

# apply custom policies if defined
Expand All @@ -188,10 +188,10 @@ def entity_statement_as_dict(self, iss: str = None, aud: list = None) -> dict:
"sub": self.sub,
"jwks": {"keys": self.jwks}
}

if policies:
data["metadata_policy"] = policies

if ta.fetch_endpoint:
data["source_endpoint"] = ta.fetch_endpoint

Expand Down Expand Up @@ -224,6 +224,9 @@ def entity_statement_as_dict(self, iss: str = None, aud: list = None) -> dict:
def entity_statement_as_json(self, iss: str = None, aud: list = None) -> str:
return json.dumps(self.entity_statement_as_dict(iss, aud))

def entity_statement_preview(self):
return self.entity_statement_as_json()

def entity_statement_as_jws(self, iss: str = None, aud: list = None) -> str:
issuer = get_first_self_trust_anchor(iss)
return create_jws(
Expand Down
9 changes: 8 additions & 1 deletion spid_cie_oidc/authority/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
from django.conf import settings
from django.urls import path

from .views import entity_list, fetch, trust_mark_status, advanced_entity_listing
from .views import (
entity_list,
fetch,
trust_mark_status,
advanced_entity_listing,
trust_marked_list
)

_PREF = getattr(settings, "OIDC_PREFIX", "")
urlpatterns = [
Expand All @@ -32,4 +38,5 @@
advanced_entity_listing,
name="oidcfed_advanced_entity_listing",
),
path(f"{_PREF}trust_marked_list", trust_marked_list, name="oidcfed_tm_list"),
]
25 changes: 25 additions & 0 deletions spid_cie_oidc/authority/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,31 @@ def entity_list(request):
return JsonResponse(list(set(entries)), safe=False)


# TODO - add the schema
# @schema(
# methods=['GET'],
# get_request_schema = {
# "application/x-www-form-urlencoded": ListRequest
# },
# get_response_schema = {
# "400": FedAPIErrorResponse,
# "404": FedAPIErrorResponse,
# "200": ListResponse
# },
# tags = ['Federation API']
# )
def trust_marked_list(request):
if request.GET.get("trust_mark_id", "").lower():
_q = {"profile__profile_id": request.GET["trust_mark_id"]}
else:
_q = {}

entries = FederationEntityAssignedProfile.objects.filter(**_q).values_list(
"descendant__sub", flat=True
)
return JsonResponse(list(set(entries)), safe=False)


@schema(
methods=['GET'],
get_request_schema = {
Expand Down
6 changes: 5 additions & 1 deletion spid_cie_oidc/entity/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ async def fetch_all(session, urls, httpc_params):


async def http_get(urls, httpc_params: dict = {}):
async with aiohttp.ClientSession(**httpc_params.get("session", {})) as session:
_con = aiohttp.TCPConnector(**httpc_params.get("connection", {}))
async with aiohttp.ClientSession(
connector=_con,
**httpc_params.get("session", {})
) as session:
text = await fetch_all(session, urls, httpc_params)
return text

Expand Down
4 changes: 2 additions & 2 deletions spid_cie_oidc/entity/jwtse.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ def create_jwe(plain_dict: Union[dict, str, int, None], jwk_dict: dict, **kwargs
if isinstance(plain_dict, dict):
_payload = json.dumps(plain_dict).encode()
elif not plain_dict:
logger.warning(f"create_jwe with null payload!")
logger.warning("create_jwe with null payload!")
_payload = ""
elif isinstance(plain_dict, (str, int)):
_payload = plain_dict
else:
logger.error(f"create_jwe with unsupported payload type!")
logger.error("create_jwe with unsupported payload type!")
_payload = ""

_keyobj = JWE_CLASS(
Expand Down
5 changes: 3 additions & 2 deletions spid_cie_oidc/entity/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@
FEDERATION_DEFAULT_EXP = getattr(settings, "FEDERATION_DEFAULT_EXP", 2880)

ENTITY_TYPE_LEAFS = [
"openid_relying_party",
"openid_provider",
"openid_relying_party",
"openid_provider",
"openid_credential_issuer",
"oauth_resource",
"wallet_provider",
"wallet_relying_party"
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/statements.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def __init__(
self.sub = self.payload["sub"]
self.iss = self.payload["iss"]
self.jwks = get_federation_jwks(self.payload, httpc_params)
if not self.jwks[0]:
if not self.jwks or not self.jwks[0]:
_msg = f"Missing jwks in the statement for {self.sub}"
logger.error(_msg)
raise MissingJwksClaim(_msg)
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def validate_entity_metadata(value):
raise ValidationError(
f"RP metadata fail {e}. "
)

# TODO - add wallet_provider and wallet_relying_party once standardized


Expand Down
1 change: 0 additions & 1 deletion spid_cie_oidc/entity/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ def resolve_entity_statement(request, format: str = "jose"):
Metadata if it's valid
we avoid any possibility to trigger a new Metadata discovery if
"""

if not all((request.GET.get("sub", None), request.GET.get("anchor", None))):
raise Http404("sub and anchor parameters are REQUIRED.")

Expand Down
2 changes: 0 additions & 2 deletions spid_cie_oidc/entity/x509.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import datetime
import os

from cryptography import x509
from cryptography.x509.oid import NameOID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ <h4 class="text-left">
</option>
{% endfor %}
</select>
<span for="id_{{ form_field.html_name }}" class="text-danger">{{ form_field.errors }}</span>
</div>

{% else %}
Expand Down Expand Up @@ -55,4 +56,4 @@ <h4 class="text-left">
<input type="submit" name="confirm" class="btn btn-lg btn-success btn-block" value="{% trans 'resolve' %}" />
</form>
</div>
{% endblock %}
{% endblock %}
8 changes: 4 additions & 4 deletions spid_cie_oidc/onboarding/tests/test_02_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ def test_resolve_statement(self):
"anchor": "http://127.0.0.1:8000"
})
self.assertEqual(res.status_code, 200)
self.assertIn("alert-error", res.content.decode())
self.assertIn(
"Failed to resolve entity statement, Please check your inserted data",
res.content.decode())
self.assertIn("text-danger", res.content.decode())
# self.assertIn(
# "Failed to resolve entity statement, Please check your inserted data",
# res.content.decode())

form_data= {
"sub": "http://127.0.0.1:8000/oidc/op",
Expand Down
4 changes: 2 additions & 2 deletions spid_cie_oidc/onboarding/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ def onboarding_resolve_statement(request):
else:
form = OnboardingCreateTrustChain()
context = {'form': form}

if form.is_valid():
context = {
'form': form,
Expand All @@ -164,6 +163,7 @@ def onboarding_resolve_statement(request):
context["resolved_statement"] = json.dumps(resultJson, indent=4)
except Exception:
messages.error(request, _('Failed to resolve entity statement, Please check your inserted data'))

return render(request, 'onboarding_resolve_statement.html', context)


Expand Down Expand Up @@ -286,7 +286,7 @@ def onboarding_decode_jwt(request):
if not form_dict.get('jwk'):
messages.error(
request,
f"JWE needs a private jwk to be decrypted"
"JWE needs a private jwk to be decrypted"
)
return render(
request, "onboarding_decode_jwt.html", context, status = 400
Expand Down
11 changes: 9 additions & 2 deletions spid_cie_oidc/provider/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
AuthenticationRequestDoc,
AuthenticationRequestSpid
)
from spid_cie_oidc.provider.schemas.authn_response import AuthenticationErrorResponse, AuthenticationErrorResponseCie, AuthenticationResponse, AuthenticationResponseCie
from spid_cie_oidc.provider.schemas.authn_response import AuthenticationErrorResponse, AuthenticationErrorResponseCie, \
AuthenticationResponse, AuthenticationResponseCie
from spid_cie_oidc.provider.schemas.introspection_request import IntrospectionRequest
from spid_cie_oidc.provider.schemas.introspection_response import IntrospectionErrorResponseCie, IntrospectionErrorResponseSpid, IntrospectionResponse
from spid_cie_oidc.provider.schemas.introspection_response import IntrospectionErrorResponseCie, \
IntrospectionErrorResponseSpid, IntrospectionResponse
from spid_cie_oidc.provider.schemas.revocation_request import RevocationRequest
from spid_cie_oidc.provider.schemas.revocation_response import RevocationErrorResponse
from spid_cie_oidc.provider.schemas.token_requests import TokenAuthnCodeRequest, TokenRefreshRequest
Expand Down Expand Up @@ -142,6 +144,11 @@
10
)

OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME = getattr(
settings,
"OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME",
2
)

OIDCFED_PROVIDER_PROFILES_DEFAULT_ACR = getattr(
settings,
Expand Down
Loading

0 comments on commit a5855da

Please sign in to comment.