Skip to content

Commit

Permalink
Refactor: rename EligibilityVerifier eligibility fields (#2272)
Browse files Browse the repository at this point in the history
  • Loading branch information
thekaveman authored Aug 6, 2024
2 parents b9bfa85 + 8880a3e commit 60e0bf4
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 94 deletions.
22 changes: 11 additions & 11 deletions benefits/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,26 @@ class SortableEligibilityVerifierAdmin(SortableAdminMixin, admin.ModelAdmin): #
def get_exclude(self, request, obj=None):
if not request.user.is_superuser:
return [
"api_auth_header",
"api_auth_key_secret_name",
"public_key",
"jwe_cek_enc",
"jwe_encryption_alg",
"jws_signing_alg",
"form_class",
"eligibility_api_auth_header",
"eligibility_api_auth_key_secret_name",
"eligibility_api_public_key",
"eligibility_api_jwe_cek_enc",
"eligibility_api_jwe_encryption_alg",
"eligibility_api_jws_signing_alg",
"eligibility_form_class",
]
else:
return super().get_exclude(request, obj)

def get_readonly_fields(self, request, obj=None):
if not request.user.is_superuser:
return [
"api_url",
"claims_provider",
"selection_label_template",
"start_template",
"unverified_template",
"eligibility_api_url",
"eligibility_start_template",
"eligibility_unverified_template",
"help_template",
"selection_label_template",
]
else:
return super().get_readonly_fields(request, obj)
Expand Down
68 changes: 68 additions & 0 deletions benefits/core/migrations/0018_rename_eligibility_api_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Generated by Django 5.0.7 on 2024-08-01 21:23

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0017_refactor_authprovider_claimsprovider"),
]

operations = [
migrations.RenameField(
model_name="eligibilityverifier",
old_name="api_auth_header",
new_name="eligibility_api_auth_header",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="api_auth_key_secret_name",
new_name="eligibility_api_auth_key_secret_name",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="jwe_cek_enc",
new_name="eligibility_api_jwe_cek_enc",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="jwe_encryption_alg",
new_name="eligibility_api_jwe_encryption_alg",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="jws_signing_alg",
new_name="eligibility_api_jws_signing_alg",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="public_key",
new_name="eligibility_api_public_key",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="api_url",
new_name="eligibility_api_url",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="form_class",
new_name="eligibility_form_class",
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="start_template",
new_name="eligibility_start_template",
),
migrations.AlterField(
model_name="eligibilityverifier",
name="eligibility_start_template",
field=models.TextField(default="eligibility/start.html"),
),
migrations.RenameField(
model_name="eligibilityverifier",
old_name="unverified_template",
new_name="eligibility_unverified_template",
),
]
51 changes: 13 additions & 38 deletions benefits/core/migrations/local_fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,10 @@
"name": "(CST) oauth claims via Login.gov",
"display_order": 1,
"active": true,
"api_url": null,
"api_auth_header": null,
"api_auth_key_secret_name": null,
"eligibility_type": 1,
"public_key": null,
"jwe_cek_enc": null,
"jwe_encryption_alg": null,
"jws_signing_alg": null,
"claims_provider": 1,
"selection_label_template": "eligibility/includes/selection-label--senior.html",
"start_template": "eligibility/start--senior.html",
"form_class": null
"eligibility_start_template": "eligibility/start--senior.html"
}
},
{
Expand All @@ -141,18 +133,10 @@
"name": "(CST) VA.gov - veteran",
"display_order": 3,
"active": true,
"api_url": null,
"api_auth_header": null,
"api_auth_key_secret_name": null,
"eligibility_type": 2,
"public_key": null,
"jwe_cek_enc": null,
"jwe_encryption_alg": null,
"jws_signing_alg": null,
"claims_provider": 2,
"selection_label_template": "eligibility/includes/selection-label--veteran.html",
"start_template": "eligibility/start--veteran.html",
"form_class": null
"eligibility_start_template": "eligibility/start--veteran.html"
}
},
{
Expand All @@ -162,19 +146,18 @@
"name": "(CST) eligibility server verifier",
"display_order": 4,
"active": true,
"api_url": "http://server:8000/verify",
"api_auth_header": "X-Server-API-Key",
"api_auth_key_secret_name": "agency-card-verifier-api-auth-key",
"eligibility_api_url": "http://server:8000/verify",
"eligibility_api_auth_header": "X-Server-API-Key",
"eligibility_api_auth_key_secret_name": "agency-card-verifier-api-auth-key",
"eligibility_type": 3,
"public_key": 1,
"jwe_cek_enc": "A256CBC-HS512",
"jwe_encryption_alg": "RSA-OAEP",
"jws_signing_alg": "RS256",
"claims_provider": null,
"eligibility_api_public_key": 1,
"eligibility_api_jwe_cek_enc": "A256CBC-HS512",
"eligibility_api_jwe_encryption_alg": "RSA-OAEP",
"eligibility_api_jws_signing_alg": "RS256",
"selection_label_template": "eligibility/includes/selection-label--cst-agency-card.html",
"start_template": "eligibility/start--cst-agency-card.html",
"form_class": "benefits.eligibility.forms.CSTAgencyCard",
"unverified_template": "eligibility/unverified--cst-agency-card.html",
"eligibility_start_template": "eligibility/start--cst-agency-card.html",
"eligibility_form_class": "benefits.eligibility.forms.CSTAgencyCard",
"eligibility_unverified_template": "eligibility/unverified--cst-agency-card.html",
"help_template": "core/includes/help--cst-agency-card.html"
}
},
Expand All @@ -185,18 +168,10 @@
"name": "(CST) CalFresh oauth claims via Login.gov",
"display_order": 2,
"active": true,
"api_url": null,
"api_auth_header": null,
"api_auth_key_secret_name": null,
"eligibility_type": 4,
"public_key": null,
"jwe_cek_enc": null,
"jwe_encryption_alg": null,
"jws_signing_alg": null,
"claims_provider": 3,
"selection_label_template": "eligibility/includes/selection-label--calfresh.html",
"start_template": "eligibility/start--calfresh.html",
"form_class": null,
"eligibility_start_template": "eligibility/start--calfresh.html",
"help_template": "core/includes/help--calfresh.html"
}
},
Expand Down
36 changes: 18 additions & 18 deletions benefits/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,24 +175,24 @@ class EligibilityVerifier(models.Model):
name = models.TextField()
display_order = models.PositiveSmallIntegerField(default=0, blank=False, null=False)
active = models.BooleanField(default=False)
api_url = models.TextField(null=True, blank=True)
api_auth_header = models.TextField(null=True, blank=True)
api_auth_key_secret_name = SecretNameField(null=True, blank=True)
eligibility_api_url = models.TextField(null=True, blank=True)
eligibility_api_auth_header = models.TextField(null=True, blank=True)
eligibility_api_auth_key_secret_name = SecretNameField(null=True, blank=True)
eligibility_type = models.ForeignKey(EligibilityType, on_delete=models.PROTECT)
# public key is used to encrypt requests targeted at this Verifier and to verify signed responses from this verifier
public_key = models.ForeignKey(PemData, related_name="+", on_delete=models.PROTECT, null=True, blank=True)
eligibility_api_public_key = models.ForeignKey(PemData, related_name="+", on_delete=models.PROTECT, null=True, blank=True)
# The JWE-compatible Content Encryption Key (CEK) key-length and mode
jwe_cek_enc = models.TextField(null=True, blank=True)
eligibility_api_jwe_cek_enc = models.TextField(null=True, blank=True)
# The JWE-compatible encryption algorithm
jwe_encryption_alg = models.TextField(null=True, blank=True)
eligibility_api_jwe_encryption_alg = models.TextField(null=True, blank=True)
# The JWS-compatible signing algorithm
jws_signing_alg = models.TextField(null=True, blank=True)
eligibility_api_jws_signing_alg = models.TextField(null=True, blank=True)
claims_provider = models.ForeignKey(ClaimsProvider, on_delete=models.PROTECT, null=True, blank=True)
selection_label_template = models.TextField()
start_template = models.TextField(null=True, blank=True)
eligibility_start_template = models.TextField(default="eligibility/start.html")
# reference to a form class used by this Verifier, e.g. benefits.app.forms.FormClass
form_class = models.TextField(null=True, blank=True)
unverified_template = models.TextField(default="eligibility/unverified.html")
eligibility_form_class = models.TextField(null=True, blank=True)
eligibility_unverified_template = models.TextField(default="eligibility/unverified.html")
help_template = models.TextField(null=True, blank=True)

class Meta:
Expand All @@ -202,29 +202,29 @@ def __str__(self):
return self.name

@property
def api_auth_key(self):
if self.api_auth_key_secret_name is not None:
return get_secret_by_name(self.api_auth_key_secret_name)
def eligibility_api_auth_key(self):
if self.eligibility_api_auth_key_secret_name is not None:
return get_secret_by_name(self.eligibility_api_auth_key_secret_name)
else:
return None

@property
def public_key_data(self):
def eligibility_api_public_key_data(self):
"""This Verifier's public key as a string."""
return self.public_key.data
return self.eligibility_api_public_key.data

@property
def uses_claims_verification(self):
"""True if this Verifier verifies via the claims provider. False otherwise."""
return self.claims_provider is not None and self.claims_provider.supports_claims_verification

def form_instance(self, *args, **kwargs):
def eligibility_form_instance(self, *args, **kwargs):
"""Return an instance of this verifier's form, or None."""
if not bool(self.form_class):
if not bool(self.eligibility_form_class):
return None

# inspired by https://stackoverflow.com/a/30941292
module_name, class_name = self.form_class.rsplit(".", 1)
module_name, class_name = self.eligibility_form_class.rsplit(".", 1)
FormClass = getattr(importlib.import_module(module_name), class_name)

return FormClass(*args, **kwargs)
Expand Down
10 changes: 5 additions & 5 deletions benefits/eligibility/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ def eligibility_from_api(verifier, form, agency):
sub, name = form.cleaned_data.get("sub"), form.cleaned_data.get("name")

client = Client(
verify_url=verifier.api_url,
headers={verifier.api_auth_header: verifier.api_auth_key},
verify_url=verifier.eligibility_api_url,
headers={verifier.eligibility_api_auth_header: verifier.eligibility_api_auth_key},
issuer=settings.ALLOWED_HOSTS[0],
agency=agency.agency_id,
jws_signing_alg=agency.jws_signing_alg,
client_private_key=agency.private_key_data,
jwe_encryption_alg=verifier.jwe_encryption_alg,
jwe_cek_enc=verifier.jwe_cek_enc,
server_public_key=verifier.public_key_data,
jwe_encryption_alg=verifier.eligibility_api_jwe_encryption_alg,
jwe_cek_enc=verifier.eligibility_api_jwe_cek_enc,
server_public_key=verifier.eligibility_api_public_key_data,
timeout=settings.REQUESTS_TIMEOUT,
)

Expand Down
10 changes: 4 additions & 6 deletions benefits/eligibility/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
ROUTE_UNVERIFIED = "eligibility:unverified"
ROUTE_ENROLLMENT = "enrollment:index"

TEMPLATE_START = "eligibility/start.html"
TEMPLATE_CONFIRM = "eligibility/confirm.html"


Expand Down Expand Up @@ -78,9 +77,8 @@ def start(request):
session.update(request, eligibility_types=[], origin=reverse(ROUTE_START))

verifier = session.verifier(request)
template = verifier.start_template or TEMPLATE_START

return TemplateResponse(request, template)
return TemplateResponse(request, verifier.eligibility_start_template)


@decorator_from_middleware(AgencySessionRequired)
Expand Down Expand Up @@ -111,7 +109,7 @@ def confirm(request):
else:
return redirect(unverified_view)

form = verifier.form_instance()
form = verifier.eligibility_form_instance()

# GET/POST for Eligibility API verification
context = {"form": form}
Expand All @@ -124,7 +122,7 @@ def confirm(request):
elif request.method == "POST":
analytics.started_eligibility(request, types_to_verify)

form = verifier.form_instance(data=request.POST)
form = verifier.eligibility_form_instance(data=request.POST)
# form was not valid, allow for correction/resubmission
if not form.is_valid():
if recaptcha.has_error(form):
Expand Down Expand Up @@ -171,4 +169,4 @@ def unverified(request):

analytics.returned_fail(request, types_to_verify)

return TemplateResponse(request, verifier.unverified_template)
return TemplateResponse(request, verifier.eligibility_unverified_template)
2 changes: 1 addition & 1 deletion benefits/oauth/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def process_request(self, request):
if verifier.uses_claims_verification:
# all good, the chosen verifier is configured correctly
return None
elif not (verifier.api_url or verifier.form_class):
elif not (verifier.eligibility_api_url or verifier.eligibility_form_class):
# the chosen verifier doesn't have Eligibility API config OR claims provider config
# this is likely a misconfiguration on the backend, not a user error
message = f"Verifier with no API or IDP config: {verifier.name} (id={verifier.id})"
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/transit-agency.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ Note that a `TransitAgency` model requires:
- HTML templates for various buttons, text and other user interface elements of the flow, including:
- `index_template`: _Required for agencies_ - Text for agency direct entry page
- `eligibility_index_template`: _Required for agencies_ - Text for Eligibility Index page
- `selection_label_template`: _Required for verifiers_ - Text and optional modals for the radio button form on the Eligibility Index page
- `eligibility_start_template`: _Required for verifiers_ - Text and optional custom styles for call to action button on the Eligibility Start page
- `enrollment_success_template`: _Required for agencies_ - Text for Enrollment Success page
- `help_template`: _Required for agencies_ - Agency-specific help questions and answers
- `selection_label_template`: _Required for verifiers_ - Text and optional modals for the radio button form on the Eligibility Index page
- `start_template`: _Required for verifiers_ - Text and optional custom styles for call to action button on the Eligibility Start page
- `sign_out_button_template`: _Required for claims providers_ - Sign out link button, used on any page after sign in
- `sign_out_link_template`: _Required for claims providers_ - Sign out link text, used on any page after sign in

Expand Down
8 changes: 4 additions & 4 deletions tests/pytest/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ def model_EligibilityVerifier(model_PemData, model_EligibilityType):
verifier = EligibilityVerifier.objects.create(
name="Test Verifier",
active=True,
api_url="https://example.com/verify",
api_auth_header="X-API-AUTH",
api_auth_key_secret_name="secret-key",
eligibility_api_url="https://example.com/verify",
eligibility_api_auth_header="X-API-AUTH",
eligibility_api_auth_key_secret_name="secret-key",
eligibility_type=model_EligibilityType,
public_key=model_PemData,
eligibility_api_public_key=model_PemData,
selection_label_template="eligibility/includes/selection-label.html",
)

Expand Down
Loading

0 comments on commit 60e0bf4

Please sign in to comment.