lms.djangoapps.verify_student package

Contents

lms.djangoapps.verify_student package#

Subpackages#

Submodules#

lms.djangoapps.verify_student.api module#

API module.

lms.djangoapps.verify_student.api.create_verification_attempt(user: User, name: str, status: str, expiration_datetime: datetime | None = None, hide_status_from_user: bool | None = False)#

Create a verification attempt.

This method is intended to be used by IDV implementation plugins to create VerificationAttempt instances.

Parameters:
  • user (User) – the user (usually a learner) performing the verification attempt

  • name (string) – the name being ID verified

  • status (string) – the initial status of the verification attempt

  • expiration_datetime (datetime, optional) – When the verification attempt expires. Defaults to None.

Returns:

The id of the created VerificationAttempt instance

Return type:

id (int)

lms.djangoapps.verify_student.api.send_approval_email(attempt)#

Send an approval email to the learner associated with the IDV attempt.

lms.djangoapps.verify_student.api.update_verification_attempt(attempt_id: int, name: str | None = None, status: str | None = None, expiration_datetime: datetime | None = None)#

Update a verification attempt.

This method is intended to be used by IDV implementation plugins to update VerificationAttempt instances.

Parameters:
  • attempt_id (*) – the verification attempt id of the attempt to update

  • name (*) – the new name being ID verified

  • status (*) – the new status of the verification attempt

  • expiration_datetime (*) – The new expiration date and time

Returns:

  • None

lms.djangoapps.verify_student.apps module#

Student Identity Verification Application Configuration

class lms.djangoapps.verify_student.apps.VerifyStudentConfig(app_name, app_module)#

Bases: AppConfig

Application Configuration for verify_student.

name = 'lms.djangoapps.verify_student'#
ready()#

Connect signal handlers.

verbose_name = 'Student Identity Verification'#

lms.djangoapps.verify_student.emails module#

ACE emails for verify_student app

lms.djangoapps.verify_student.emails.send_verification_approved_email(context)#

Sends email to a learner when ID verification has been approved.

lms.djangoapps.verify_student.emails.send_verification_confirmation_email(context)#

Send an email confirming that the user submitted photos for initial verification.

lms.djangoapps.verify_student.exceptions module#

Exceptions for the verify student app

exception lms.djangoapps.verify_student.exceptions.VerificationAttemptInvalidStatus#

Bases: Exception

exception lms.djangoapps.verify_student.exceptions.WindowExpiredException#

Bases: Exception

lms.djangoapps.verify_student.image module#

Image encoding helpers for the verification app.

exception lms.djangoapps.verify_student.image.InvalidImageData#

Bases: Exception

The provided image data could not be decoded.

lms.djangoapps.verify_student.image.decode_image_data(data)#

Decode base64-encoded image data.

Parameters:

data (str) – The raw image data, base64-encoded.

Returns:

str

Raises:

InvalidImageData – The image data could not be decoded.

lms.djangoapps.verify_student.message_types module#

ACE message types for the verify_student module.

class lms.djangoapps.verify_student.message_types.VerificationApproved(*args, **kwargs)#

Bases: BaseMessageType

A message to the learner when their ID verification has been approved.

APP_LABEL = 'verify_student'#
Name = 'verificationapproved'#
class lms.djangoapps.verify_student.message_types.VerificationExpiry(*args, **kwargs)#

Bases: BaseMessageType

APP_LABEL = 'verify_student'#
Name = 'verificationexpiry'#
class lms.djangoapps.verify_student.message_types.VerificationSubmitted(*args, **kwargs)#

Bases: BaseMessageType

A confirmation message to the learner when their ID verification has been submitted.

APP_LABEL = 'verify_student'#
Name = 'verificationsubmitted'#

lms.djangoapps.verify_student.models module#

Models for Student Identity Verification

This is where we put any models relating to establishing the real-life identity of a student over a period of time. Right now, the only models are the abstract PhotoVerification, and its one concrete implementation SoftwareSecurePhotoVerification. The hope is to keep as much of the photo verification process as generic as possible.

class lms.djangoapps.verify_student.models.IDVerificationAttempt(*args, **kwargs)#

Bases: StatusModel

Each IDVerificationAttempt represents a Student’s attempt to establish their identity through one of several methods that inherit from this Model, including PhotoVerification and SSOVerification.

class Meta#

Bases: object

abstract = False#
app_label = 'verify_student'#
ordering = ['-created_at']#
STATUS = Choices(('created', 'created', 'created'), ('ready', 'ready', 'ready'), ('submitted', 'submitted', 'submitted'), ('must_retry', 'must_retry', 'must_retry'), ('approved', 'approved', 'approved'), ('denied', 'denied', 'denied'))#
active_at_datetime(deadline)#

Check whether the verification was active at a particular datetime.

Parameters:

deadline (datetime) – The date at which the verification was active (created before and expiration datetime is after today).

Returns:

bool

created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

expiration_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property expiration_datetime#

Account for old DB entries which have expiration_date set to NULL.

expiration_default()#
get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
get_status_display(*, field=<model_utils.fields.StatusField: status>)#
name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

should_display_status_to_user()#

Whether or not the status from this attempt should be displayed to the user.

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.ManualVerification(*args, **kwargs)#

Bases: IDVerificationAttempt

Each ManualVerification represents a user’s verification that bypasses the need for any other verification.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

approved = <model_utils.managers.QueryManager object>#
created = <model_utils.managers.QueryManager object>#
created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

denied = <model_utils.managers.QueryManager object>#
expiration_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
get_status_display(*, field=<model_utils.fields.StatusField: status>)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

must_retry = <model_utils.managers.QueryManager object>#
name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
ready = <model_utils.managers.QueryManager object>#
reason#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

should_display_status_to_user()#

Whether or not the status should be displayed to the user.

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

submitted = <model_utils.managers.QueryManager object>#
updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.PhotoVerification(*args, **kwargs)#

Bases: IDVerificationAttempt

Each PhotoVerification represents a Student’s attempt to establish their identity by uploading a photo of themselves and a picture ID. An attempt actually has a number of fields that need to be filled out at different steps of the approval process. While it’s useful as a Django Model for the querying facilities, you should only edit a `PhotoVerification` object through the methods provided. Initialize them with a user:

attempt = PhotoVerification(user=user)

We track this attempt through various states:

created

Initial creation and state we’re in after uploading the images.

ready

The user has uploaded their images and checked that they can read the images. There’s a separate state here because it may be the case that we don’t actually submit this attempt for review until payment is made.

submitted

Submitted for review. The review may be done by a staff member or an external service. The user cannot make changes once in this state.

must_retry

We submitted this, but there was an error on submission (i.e. we did not get a 200 when we POSTed to Software Secure)

approved

An admin or an external service has confirmed that the user’s photo and photo ID match up, and that the photo ID’s name matches the user’s.

denied

The request has been denied. See error_msg for details on why. An admin might later override this and change to approved, but the student cannot re-open this attempt – they have to create another attempt and submit it instead.

Because this Model inherits from IDVerificationAttempt, which inherits from StatusModel, we can also do things like:

attempt.status == PhotoVerification.STATUS.created attempt.status == “created” pending_requests = PhotoVerification.submitted.all()

class Meta#

Bases: object

abstract = False#
app_label = 'verify_student'#
ordering = ['-created_at']#
approve(user_id=None, service='')#

Approve this attempt. user_id

Valid attempt statuses when calling this method:

submitted, approved, denied

Status after method completes: approved

Other fields that will be set by this method:

reviewed_by_user_id, reviewed_by_service, error_msg

State Transitions:

submittedapproved

This is the usual flow, whether initiated by a staff user or an external validation service.

approvedapproved

No-op. First one to approve it wins.

deniedapproved

This might happen if a staff member wants to override a decision made by an external service or another staff member (say, in response to a support request). In this case, the previous values of reviewed_by_user_id and reviewed_by_service will be changed to whoever is doing the approving, and error_msg will be reset. The only record that this record was ever denied would be in our logs. This should be a relatively rare occurrence.

created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

deny(error_msg, error_code='', reviewing_user=None, reviewing_service='')#

Deny this attempt.

Valid attempt statuses when calling this method:

submitted, approved, denied

Status after method completes: denied

Other fields that will be set by this method:

reviewed_by_user_id, reviewed_by_service, error_msg, error_code

State Transitions:

submitteddenied

This is the usual flow, whether initiated by a staff user or an external validation service.

approveddenied

This might happen if a staff member wants to override a decision made by an external service or another staff member, or just correct a mistake made during the approval process. In this case, the previous values of reviewed_by_user_id and reviewed_by_service will be changed to whoever is doing the denying. The only record that this record was ever approved would be in our logs. This should be a relatively rare occurrence.

denieddenied

Update the error message and reviewing_user/reviewing_service. Just lets you amend the error message in case there were additional details to be made.

display#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

error_code#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

error_msg#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

expiration_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

face_image_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
get_status_display(*, field=<model_utils.fields.StatusField: status>)#
mark_must_retry(error='')#

Set the attempt status to must_retry. Mark that this attempt could not be completed because of a system error. Status should be moved to must_retry. For example, if Software Secure service is down and we couldn’t process the request even after retrying.

Valid attempt statuses when calling this method:

ready, submitted

Status after method completes: must_retry

State Transitions:

→ → → must_retry ↑ ↑ ↓

readysubmitted

mark_ready()#

Mark that the user data in this attempt is correct. In order to succeed, the user must have uploaded the necessary images (face_image_url, photo_id_image_url). This method will also copy their name from their user profile. Prior to marking it ready, we read this value directly from their profile, since they’re free to change it. This often happens because people put in less formal versions of their name on signup, but realize they want something different to go on a formal document.

Valid attempt statuses when calling this method:

created

Status after method completes: ready

Other fields that will be set by this method:

name

State Transitions:

createdready

This is what happens when the user confirms to us that the pictures they uploaded are good. Note that we don’t actually do a submission anywhere yet.

mark_submit()#

Submit this attempt. Valid attempt statuses when calling this method:

ready, must_retry

Status after method completes: submitted

State Transitions:

→ → → must_retry ↑ ↑ ↓

readysubmitted

name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

parsed_error_msg()#

Sometimes, the error message we’ve received needs to be parsed into something more human readable

The default behavior is to return the current error message as is.

photo_id_image_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

receipt_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod retire_user(user_id)#

Retire user as part of GDPR Phase I Returns ‘True’ if records found

Parameters:

user_id – int

Returns:

bool

reviewing_service#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

reviewing_user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

reviewing_user_id#
status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

submitted_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

system_error(error_msg, error_code='', reviewing_user=None, reviewing_service='')#

Mark that this attempt could not be completed because of a system error. Status should be moved to must_retry. For example, if Software Secure reported to us that they couldn’t process our submission because they couldn’t decrypt the image we sent.

updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

upload_face_image(img_data)#
upload_photo_id_image(img_data)#
user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.SSOVerification(*args, **kwargs)#

Bases: IDVerificationAttempt

Each SSOVerification represents a Student’s attempt to establish their identity by signing in with SSO. ID verification through SSO bypasses the need for photo verification.

exception DoesNotExist#

Bases: ObjectDoesNotExist

IDENTITY_PROVIDER_TYPE_CHOICES = (('common.djangoapps.third_party_auth.models.OAuth2ProviderConfig', 'OAuth2 Provider'), ('common.djangoapps.third_party_auth.models.SAMLProviderConfig', 'SAML Provider'), ('common.djangoapps.third_party_auth.models.LTIProviderConfig', 'LTI Provider'))#
LTI = 'common.djangoapps.third_party_auth.models.LTIProviderConfig'#
exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

OAUTH2 = 'common.djangoapps.third_party_auth.models.OAuth2ProviderConfig'#
SAML = 'common.djangoapps.third_party_auth.models.SAMLProviderConfig'#
approved = <model_utils.managers.QueryManager object>#
created = <model_utils.managers.QueryManager object>#
created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

denied = <model_utils.managers.QueryManager object>#
expiration_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_identity_provider_type_display(*, field=<django.db.models.fields.CharField: identity_provider_type>)#
get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
get_status_display(*, field=<model_utils.fields.StatusField: status>)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

identity_provider_slug#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

identity_provider_type#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

must_retry = <model_utils.managers.QueryManager object>#
name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
ready = <model_utils.managers.QueryManager object>#
send_approval_signal(approved_by='None')#

Send a signal indicating that this verification was approved.

should_display_status_to_user()#

Whether or not the status from this attempt should be displayed to the user.

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

submitted = <model_utils.managers.QueryManager object>#
updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.SSPVerificationRetryConfig(*args, **kwargs)#

Bases: ConfigurationModel

SSPVerificationRetryConfig used to inject arguments to retry_failed_photo_verifications management command

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

arguments#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

change_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

changed_by#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

changed_by_id#
enabled#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=True, **kwargs)#
get_previous_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class lms.djangoapps.verify_student.models.SoftwareSecurePhotoVerification(*args, **kwargs)#

Bases: PhotoVerification

Model to verify identity using a service provided by Software Secure. Much of the logic is inherited from PhotoVerification, but this class encrypts the photos.

Software Secure (http://www.softwaresecure.com/) is a remote proctoring service that also does identity verification. A student uses their webcam to upload two images: one of their face, one of a photo ID. Due to the sensitive nature of the data, the following security precautions are taken:

  1. The snapshot of their face is encrypted using AES-256 in CBC mode. All face photos are encrypted with the same key, and this key is known to both Software Secure and edx-platform.

  2. The snapshot of a user’s photo ID is also encrypted using AES-256, but the key is randomly generated using os.urandom. Every verification attempt has a new key. The AES key is then encrypted using a public key provided by Software Secure. We store only the RSA-encrypted AES key. Since edx-platform does not have Software Secure’s private RSA key, it means that we can no longer even read photo ID.

  3. The encrypted photos are base64 encoded and stored in an S3 bucket that edx-platform does not have read access to.

Note: this model handles initial verifications (which you must perform at the time you register for a verified cert).

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

approved = <model_utils.managers.QueryManager object>#
copy_id_photo_from#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

copy_id_photo_from_id#
create_request(copy_id_photo_from=None)#

Construct the HTTP request to the photo verification service.

Keyword Arguments:

copy_id_photo_from (SoftwareSecurePhotoVerification) – If provided, re-send the ID photo data from this attempt. This is used for re-verification, in which new face photos are sent with previously-submitted ID photos.

Returns:

tuple of (header, body), where both header and body are dictionaries.

created = <model_utils.managers.QueryManager object>#
created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

denied = <model_utils.managers.QueryManager object>#
display#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

download_face_image()#

Download the associated face image from storage

download_photo_id_image()#

Download the associated id image from storage

error_code#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

error_msg#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

expiration_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

expiry_email_date#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

face_image_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod get_initial_verification(user, earliest_allowed_date=None)#

Get initial verification for a user with the ‘photo_id_key’.

Parameters:
  • user (User) – user object

  • earliest_allowed_date (datetime) – override expiration date for initial verification

Returns:

SoftwareSecurePhotoVerification (object) or None

get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
classmethod get_recent_verification(user)#

Return the most recent approved verification of user

Keyword Arguments:

user (User) – The user for which the most recent approved verification is fetched

Returns:

SoftwareSecurePhotoVerification (object) or None

get_status_display(*, field=<model_utils.fields.StatusField: status>)#
classmethod get_verification_from_receipt(receipt_id)#

Get a verification for a user based on the photo receipt_id

Parameters:

receipt_id (String) – receipt ID of the user photo or ID photo

Returns:

SoftwareSecurePhotoVerification (object) or None

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

image_url(name, override_receipt_id=None)#

We dynamically generate this, since we want it the expiration clock to start when the message is created, not when the record is created.

Parameters:

name (str) – Name of the image (e.g. “photo_id” or “face”)

Keyword Arguments:

override_receipt_id (str) – If provided, use this receipt ID instead of the ID for this attempt. This is useful for reverification where we need to construct a URL to a previously-submitted photo ID image.

Returns:

The expiring URL for the image.

Return type:

string

must_retry = <model_utils.managers.QueryManager object>#
name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
parsed_error_msg()#

Parse the error messages we receive from SoftwareSecure

Error messages are written in the form:

[{“photoIdReasons”: [“Not provided”]}]

Returns:

List of error messages.

Return type:

str[]

photo_id_image_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

photo_id_key#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

ready = <model_utils.managers.QueryManager object>#
receipt_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

request_message_txt()#

This is the body of the request we send across. This is never actually used in the code, but exists for debugging purposes – you can call print attempt.request_message_txt() on the console and get a readable rendering of the request that would be sent across, without actually sending anything.

reviewing_service#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

reviewing_user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

reviewing_user_id#
should_display_status_to_user()#

Whether or not the status from this attempt should be displayed to the user.

softwaresecurephotoverification_set#

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

submit(copy_id_photo_from=None)#

Submit our verification attempt to Software Secure for validation. This will set our status to “submitted”, if the post is successful or will set to “must_retry” if the post fails.

Keyword Arguments:

copy_id_photo_from (SoftwareSecurePhotoVerification) – If provided, re-send the ID photo data from this attempt. This is used for re-verification, in which new face photos are sent with previously-submitted ID photos.

submitted = <model_utils.managers.QueryManager object>#
submitted_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod update_expiry_email_date_for_user(user, email_config)#

Updates the expiry_email_date to send expiry email if the most recent approved verification for the user is expired.

Keyword Arguments:
  • user (User) – user object

  • email_config (dict) – Contains configuration related to verification expiry email

updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

upload_face_image(img_data)#

Upload an image of the user’s face. img_data should be a raw bytestream of a PNG image. This method will take the data, encrypt it using our FACE_IMAGE_AES_KEY, encode it with base64 and save it to the storage backend.

Yes, encoding it to base64 adds compute and disk usage without much real benefit, but that’s what the other end of this API is expecting to get.

upload_photo_id_image(img_data)#

Upload an the user’s photo ID image. img_data should be a raw bytestream of a PNG image. This method will take the data, encrypt it using a randomly generated AES key, encode it with base64 and save it to the storage backend. The random key is also encrypted using Software Secure’s public RSA key and stored in our photo_id_key field.

Yes, encoding it to base64 adds compute and disk usage without much real benefit, but that’s what the other end of this API is expecting to get.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.VerificationAttempt(*args, **kwargs)#

Bases: StatusModel

The model represents impelementation-agnostic information about identity verification (IDV) attempts.

Plugins that implement forms of IDV can store information about IDV attempts in this model for use across the platform.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

STATUS = Choices((<VerificationAttemptStatus.CREATED: 'created'>, <VerificationAttemptStatus.CREATED: 'created'>, <VerificationAttemptStatus.CREATED: 'created'>), (<VerificationAttemptStatus.PENDING: 'pending'>, <VerificationAttemptStatus.PENDING: 'pending'>, <VerificationAttemptStatus.PENDING: 'pending'>), (<VerificationAttemptStatus.APPROVED: 'approved'>, <VerificationAttemptStatus.APPROVED: 'approved'>, <VerificationAttemptStatus.APPROVED: 'approved'>), (<VerificationAttemptStatus.DENIED: 'denied'>, <VerificationAttemptStatus.DENIED: 'denied'>, <VerificationAttemptStatus.DENIED: 'denied'>))#
active_at_datetime(deadline)#

Check whether the verification was active at a particular datetime.

Parameters:

deadline (datetime) – The date at which the verification was active (created before and expiration datetime is after today).

Returns:

bool

approved = <model_utils.managers.QueryManager object>#
created = <model_utils.managers.QueryManager object>#
created_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

denied = <model_utils.managers.QueryManager object>#
expiration_datetime#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
get_next_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=True, **kwargs)#
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
get_previous_by_status_changed(*, field=<model_utils.fields.MonitorField: status_changed>, is_next=False, **kwargs)#
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
get_status_display(*, field=<model_utils.fields.StatusField: status>)#
hide_status_from_user#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
pending = <model_utils.managers.QueryManager object>#
classmethod retire_user(user_id)#

Retire user as part of GDPR pipeline

Parameters:

user_id – int

should_display_status_to_user()#

When called, returns true or false based on the type of VerificationAttempt

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

status_changed#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

updated_at#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

user_id#
class lms.djangoapps.verify_student.models.VerificationDeadline(*args, **kwargs)#

Bases: TimeStampedModel

Represent a verification deadline for a particular course.

The verification deadline is the datetime after which users are no longer allowed to submit photos for initial verification in a course.

Note that this is NOT the same as the “upgrade” deadline, after which a user is no longer allowed to upgrade to a verified enrollment.

If no verification deadline record exists for a course, then that course does not have a deadline. This means that users can submit photos at any time.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

course_key#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

created#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

deadline#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod deadline_for_course(course_key)#

Retrieve the verification deadline for a particular course.

Parameters:

course_key (CourseKey) – The identifier for the course.

Returns:

datetime or None

deadline_is_explicit#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod deadlines_for_enrollments(enrollments_qs)#

Retrieve verification deadlines for a user’s enrolled courses.

Parameters:

enrollments_qs – CourseEnrollment queryset. For performance reasons we want the queryset here instead of passing in a big list of course_keys in an “SELECT IN” query. If we have a queryset, Django is smart enough to do a performant subquery at the MySQL layer instead of passing down all the course_keys through Python.

Returns:

Map of course keys to datetimes (verification deadlines)

Return type:

dict

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_deadline(*, field=<django.db.models.fields.DateTimeField: deadline>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_deadline(*, field=<django.db.models.fields.DateTimeField: deadline>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

modified#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
classmethod set_deadline(course_key, deadline, is_explicit=False)#

Configure the verification deadline for a course.

If deadline is None, then the course will have no verification deadline. In this case, users will be able to verify for the course at any time.

Parameters:
  • course_key (CourseKey) – Identifier for the course.

  • deadline (datetime or None) – The verification deadline.

exception lms.djangoapps.verify_student.models.VerificationException#

Bases: Exception

lms.djangoapps.verify_student.models.generateUUID()#

Utility function; generates UUIDs

lms.djangoapps.verify_student.models.status_before_must_be(*valid_start_statuses)#

Helper decorator with arguments to make sure that an object with a status attribute is in one of a list of acceptable status states before a method is called. You could use it in a class definition like:

@status_before_must_be(“submitted”, “approved”, “denied”) def refund_user(self, user_id):

# Do logic here…

If the object has a status that is not listed when the refund_user method is invoked, it will throw a VerificationException. This is just to avoid distracting boilerplate when looking at a Model that needs to go through a workflow process.

lms.djangoapps.verify_student.services module#

Implementation of abstraction layer for other parts of the system to make queries related to ID Verification.

class lms.djangoapps.verify_student.services.IDVerificationService#

Bases: object

Learner verification service interface for callers within edx-platform.

classmethod get_expiration_datetime(user, statuses)#

Check whether the user has a verification with one of the given statuses and return the “expiration_datetime” of most recent verification that matches one of the given statuses.

Parameters:
  • user (Object) – User

  • statuses – List of verification statuses (e.g., [‘approved’])

Returns:

expiration_datetime of most recent verification that matches one of the given statuses.

Return type:

expiration_datetime

classmethod get_verified_user_ids(users)#

Given a list of users, returns an iterator of user ids that have non-expired verifications of any type.

classmethod get_verify_location(course_id=None)#
Returns a string:

Returns URL for IDV on Account Microfrontend

classmethod user_has_valid_or_pending(user)#

Check whether the user has an active or pending verification attempt

Returns:

True or False according to existence of valid verifications

Return type:

bool

classmethod user_is_verified(user)#

Return whether or not a user has satisfactorily proved their identity. Depending on the policy, this can expire after some period of time, so a user might have to renew periodically.

classmethod user_status(user)#

Returns the status of the user based on their past verification attempts, and any corresponding error messages.

If no such verification exists, returns ‘none’ If verification has expired, returns ‘expired’ If the verification has been approved, returns ‘approved’ If the verification process is still ongoing, returns ‘pending’ If the verification has been denied and the user must resubmit photos, returns ‘must_reverify’

This checks most recent verification

classmethod verification_status_for_user(user, user_enrollment_mode, user_is_verified=None)#

Returns the verification status for use in grade report.

classmethod verifications_for_user(user)#

Return a list of all verifications associated with the given user.

class lms.djangoapps.verify_student.services.XBlockVerificationService#

Bases: object

Learner verification XBlock service.

get_status(user_id)#

Returns the user’s current photo verification status.

Parameters:

user_id – the user’s id

Returns: one of the following strings

‘none’ - no such verification exists ‘expired’ - verification has expired ‘approved’ - verification has been approved ‘pending’ - verification process is still ongoing ‘must_reverify’ - verification has been denied and user must resubmit photos

reverify_url()#

Returns the URL for a user to verify themselves.

lms.djangoapps.verify_student.ssencrypt module#

NOTE: Anytime a key is passed into a function here, we assume it’s a raw byte string. It should not be a string representation of a hex value. In other words, passing the str value of “32fe72aaf2abb44de9e161131b5435c8d37cbdb6f5df242ae860b283115f2dae” is bad. You want to pass in the result of calling .decode(‘hex’) on that, so this instead: “‘2þrªò«´MéáaT5ÈÓ|½¶õß$*è`²ƒ_-®’”

An RSA public key can be in any of the following formats: * X.509 subjectPublicKeyInfo DER SEQUENCE (binary or PEM encoding) * PKCS#1 RSAPublicKey DER SEQUENCE (binary or PEM encoding) * OpenSSH (textual public key only)

An RSA private key can be in any of the following formats: * PKCS#1 RSAPrivateKey DER SEQUENCE (binary or PEM encoding) * PKCS#8 PrivateKeyInfo DER SEQUENCE (binary or PEM encoding)

lms.djangoapps.verify_student.ssencrypt.aes_cipher_from_key(key)#

Given an AES key, return a Cipher object that has encryptor() and decryptor() methods. It will create the cipher to use CBC mode, and create the initialization vector as Software Secure expects it.

lms.djangoapps.verify_student.ssencrypt.aes_decrypt(encrypted_data, key)#

Decrypt encrypted_data using key

lms.djangoapps.verify_student.ssencrypt.aes_encrypt(data, key)#

Return a version of the data that has been encrypted to

lms.djangoapps.verify_student.ssencrypt.body_string(body_dict, prefix='')#

Return a canonical string representation of the body of a JSON request or response. This canonical representation will be used as an input to the hashing used to generate a signature.

lms.djangoapps.verify_student.ssencrypt.decode_and_decrypt(encoded_data, key)#

Decrypts and decodes data using `key’

lms.djangoapps.verify_student.ssencrypt.encrypt_and_encode(data, key)#

Encrypts and encodes data using `key’

lms.djangoapps.verify_student.ssencrypt.generate_aes_iv(key)#

Return the initialization vector Software Secure expects for a given AES key (they hash it a couple of times and take a substring).

lms.djangoapps.verify_student.ssencrypt.generate_signed_message(method, headers_dict, body_dict, access_key, secret_key)#

Returns a (message, signature) pair.

lms.djangoapps.verify_student.ssencrypt.has_valid_signature(method, headers_dict, body_dict, access_key, secret_key)#

Given a message (either request or response), say whether it has a valid signature or not.

lms.djangoapps.verify_student.ssencrypt.header_string(headers_dict)#

Given a dictionary of headers, return a canonical string representation.

lms.djangoapps.verify_student.ssencrypt.pad(data)#

Pad the given data such that it fits into the proper AES block size

lms.djangoapps.verify_student.ssencrypt.random_aes_key()#
lms.djangoapps.verify_student.ssencrypt.rsa_decrypt(data, rsa_priv_key_bytes)#

When given some data and an RSA private key, decrypt the data

lms.djangoapps.verify_student.ssencrypt.rsa_encrypt(data, rsa_pub_key_bytes)#

rsa_pub_key_bytes is a byte sequence with the public key

lms.djangoapps.verify_student.ssencrypt.signing_format_message(method, headers_dict, body_dict)#

Given a dictionary of headers and a dictionary of the JSON for the body, will return a str that represents the normalized version of this messsage that will be used to generate a signature.

lms.djangoapps.verify_student.ssencrypt.unpad(padded_data)#

remove all padding from padded_data

lms.djangoapps.verify_student.statuses module#

Status enums for verify_student.

class lms.djangoapps.verify_student.statuses.VerificationAttemptStatus(*values)#

Bases: StrEnum

This class describes valid statuses for a verification attempt to be in.

APPROVED = 'approved'#
CREATED = 'created'#
DENIED = 'denied'#
PENDING = 'pending'#

lms.djangoapps.verify_student.tasks module#

Django Celery tasks for service status app

class lms.djangoapps.verify_student.tasks.BaseSoftwareSecureTask#

Bases: Task

Base task class for use with Software Secure request.

Permits updating information about user attempt in correspondence to submitting request to software secure.

abstract = True#

Deprecated attribute abstract here for compatibility.

after_return(status, retval, task_id, args, kwargs, einfo)#

If max retries have reached and task status is still failing, mark user submission with “must_retry” so that it can be retried latter.

ignore_result = False#

If enabled the worker won’t store task state and return values for this task. Defaults to the :setting:`task_ignore_result` setting.

on_success(retval, task_id, args, kwargs)#

Update SoftwareSecurePhotoVerification object corresponding to this task with info about success.

Updates user verification attempt to “submitted” if the response was ok otherwise set it to “must_retry”.

Assumes retval is a dict containing the task’s result, with the following keys:

‘response_ok’: boolean, indicating if the response was ok ‘response_text’: string, indicating the response text in case of failure.

priority = None#

Default task priority.

rate_limit = None#

None (no rate limit), ‘100/s’ (hundred tasks a second), ‘100/m’ (hundred tasks a minute),`’100/h’` (hundred tasks an hour)

Type:

Rate limit for this task type. Examples

reject_on_worker_lost = None#

Even if acks_late is enabled, the worker will acknowledge tasks when the worker process executing them abruptly exits or is signaled (e.g., :sig:`KILL`/:sig:`INT`, etc).

Setting this to true allows the message to be re-queued instead, so that the task will execute again by the same worker, or another worker.

Warning: Enabling this can cause message loops; make sure you know what you’re doing.

request_stack = <celery.utils.threads._LocalStack object>#

Task request stack, the current request will be the topmost.

serializer = 'json'#

The name of a serializer that are registered with kombu.serialization.registry. Default is ‘json’.

store_errors_even_if_ignored = True#

When enabled errors will be stored even if the task is otherwise configured to ignore results.

track_started = True#

If enabled the task will report its status as ‘started’ when the task is executed by a worker. Disabled by default as the normal behavior is to not report that level of granularity. Tasks are either pending, finished, or waiting to be retried.

Having a ‘started’ status can be useful for when there are long running tasks and there’s a need to report what task is currently running.

The application default can be overridden using the :setting:`task_track_started` setting.

typing = True#

Enable argument checking. You can set this to false if you don’t want the signature to be checked when calling the task. Defaults to app.strict_typing.

lms.djangoapps.verify_student.toggles module#

Toggles for verify_student app

lms.djangoapps.verify_student.toggles.use_new_templates_for_id_verification_emails()#

lms.djangoapps.verify_student.urls module#

URL definitions for the verify_student app.

lms.djangoapps.verify_student.utils module#

Common Utilities for the verify_student application.

lms.djangoapps.verify_student.utils.active_verifications(candidates, deadline)#

Based on the deadline, only return verification attempts that are considered active (non-expired and wasn’t created for future)

lms.djangoapps.verify_student.utils.auto_verify_for_testing_enabled(override=None)#

If AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING is True, we want to skip posting anything to Software Secure.

Bypass posting anything to Software Secure if auto verify feature for testing is enabled. We actually don’t even create the message because that would require encryption and message signing that rely on settings.VERIFY_STUDENT values that aren’t set in dev. So we just pretend like we successfully posted.

lms.djangoapps.verify_student.utils.can_verify_now(verification_status, expiration_datetime)#

Returns whether one is eligible for verification now based on status and expiration.

Parameters:
  • verification_status (str)

  • expiration_datetime (datetime)

Returns: bool

lms.djangoapps.verify_student.utils.earliest_allowed_verification_date()#

Returns the earliest allowed date given the settings

lms.djangoapps.verify_student.utils.is_verification_expiring_soon(expiration_datetime)#

Returns True if verification is expiring within EXPIRING_SOON_WINDOW.

lms.djangoapps.verify_student.utils.most_recent_verification(verification_sets)#

Return the most recent verification (by updated date) given querysets for multiple types of verifications. Photo, sso and manual are the current use.

Parameters:

sets (tuple or other iterable of verification)

Returns:

The most recent verification.

lms.djangoapps.verify_student.utils.submit_request_to_ss(user_verification, copy_id_photo_from)#

Submit our verification attempt to Software Secure for validation.

Submits the task to software secure and If the task creation fails, set the verification status to “must_retry”.

lms.djangoapps.verify_student.utils.verification_for_datetime(deadline, candidates)#

Find a verification in a set that applied during a particular datetime.

A verification is considered “active” during a datetime if: 1) The verification was created before the datetime, and 2) The verification is set to expire after the datetime.

Note that verification status is not considered here, just the start/expire dates.

If multiple verifications were active at the deadline, returns the most recently created one.

Parameters:
  • deadline (datetime) – The datetime at which the verification applied. If None, then return the most recently created candidate.

  • candidates (list of `PhotoVerification`s) – Potential verifications to search through.

Returns:

A photo verification that was active at the deadline.

If no verification was active, return None.

Return type:

PhotoVerification

lms.djangoapps.verify_student.views module#

Views for the verification flow

class lms.djangoapps.verify_student.views.DecryptFaceImageView(**kwargs)#

Bases: APIView

Endpoint to retrieve decrypted IDV face image data. Can only be used on stage.

get(request, receipt_id)#

Endpoint used for decrypting images on stage based on a given receipt ID GET /verify_student/decrypt-idv-images/face/{receipt_id}

Returns:

200 OK {

img

}

class lms.djangoapps.verify_student.views.DecryptPhotoIDImageView(**kwargs)#

Bases: APIView

Endpoint to retrieve decrypted IDV photo ID image data. Can only be used on stage.

get(request, receipt_id)#

Endpoint used for decrypting images on stage based on a given receipt ID GET /verify_student/decrypt-idv-images/photo-id/{receipt_id}

Returns:

200 OK {

img

}

class lms.djangoapps.verify_student.views.PayAndVerifyView(**kwargs)#

Bases: View

View for the “verify and pay” flow.

This view is somewhat complicated, because the user can enter it from a number of different places:

  • From the “choose your track” page.

  • After completing payment.

  • From the dashboard in order to complete verification.

  • From the dashboard in order to upgrade to a verified track.

The page will display different steps and requirements depending on:

  • Whether the user has submitted a photo verification recently.

  • Whether the user has paid for the course.

  • How the user reached the page (mostly affects messaging)

We are also super-paranoid about how users reach this page. If they somehow aren’t enrolled, or the course doesn’t exist, or they’ve unenrolled, or they’ve already paid/verified, … then we try to redirect them to the page with the most appropriate messaging (including the dashboard).

Note that this page does NOT handle re-verification (photo verification that was denied or had an error); that is handled by the “reverify” view.

ACCOUNT_ACTIVATION_REQ = 'account-activation-required'#
ALL_STEPS = ['intro-step', 'make-payment-step', 'face-photo-step', 'id-photo-step', 'review-photos-step', 'enrollment-confirmation-step']#
ENROLLMENT_CONFIRMATION_STEP = 'enrollment-confirmation-step'#
FACE_PHOTO_STEP = 'face-photo-step'#
FIRST_TIME_VERIFY_MSG = 'first-time-verify'#
ID_PHOTO_STEP = 'id-photo-step'#
INTRO_STEP = 'intro-step'#
MAKE_PAYMENT_STEP = 'make-payment-step'#
PAYMENT_STEPS = ['make-payment-step']#
PHOTO_ID_REQ = 'photo-id-required'#
REVIEW_PHOTOS_STEP = 'review-photos-step'#
SKIP_STEPS = ['intro-step']#
STEP_REQUIREMENTS = {'face-photo-step': ['webcam-required'], 'id-photo-step': ['photo-id-required', 'webcam-required']}#
STEP_TITLES = {'enrollment-confirmation-step': 'Enrollment confirmation', 'face-photo-step': 'Take photo', 'id-photo-step': 'Take a photo of your ID', 'intro-step': 'Intro', 'make-payment-step': 'Make payment', 'review-photos-step': 'Review your info'}#
UPGRADE_DEADLINE = 'upgrade'#
UPGRADE_MSG = 'upgrade'#
VERIFICATION_DEADLINE = 'verification'#
VERIFICATION_STEPS = ['face-photo-step', 'id-photo-step', 'review-photos-step', 'enrollment-confirmation-step']#
VERIFY_LATER_MSG = 'verify-later'#
VERIFY_NOW_MSG = 'verify-now'#
WEBCAM_REQ = 'webcam-required'#
add_utm_params_to_url(url)#
get(request, course_id, always_show_payment=False, current_step=None, message='first-time-verify')#

Render the payment and verification flow.

Parameters:
  • request (HttpRequest) – The request object.

  • course_id (unicode) – The ID of the course the user is trying to enroll in.

Keyword Arguments:
  • always_show_payment (bool) – If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying.

  • current_step (string) – The current step in the flow.

  • message (string) – The messaging to display.

Returns:

HttpResponse

Raises:

Http404 – The course does not exist or does not have a verified mode.

class lms.djangoapps.verify_student.views.PhotoUrlsView(**kwargs)#

Bases: APIView

This can be used to help debug IDV photos

get(request, receipt_id)#

Endpoint for retrieving photo urls for IDV GET /verify_student/photo-urls/{receipt_id}

Returns:

200 OK {

”EdX-ID”: receipt_id, “ExpectedName”: user profile name, “PhotoID”: id photo S3 url, “PhotoIDKey”: encrypted photo id key, “UserPhoto”: face photo S3 url, “UserPhotoKey”: encrypted user photo key,

}

class lms.djangoapps.verify_student.views.ReverifyView(**kwargs)#

Bases: View

Reverification occurs when a user’s initial verification is denied or expires. When this happens, users can re-submit photos through the re-verification flow.

Unlike in-course reverification, this flow requires users to submit both face and ID photos. In contrast, during in-course reverification, students submit only face photos, which are matched against the ID photo the user submitted during initial verification.

get(request)#

Render the reverification flow.

Most of the work is done client-side by composing the same Backbone views used in the initial verification flow.

class lms.djangoapps.verify_student.views.SubmitPhotosView(**kwargs)#

Bases: View

End-point for submitting photos for verification.

dispatch(request, *args, **kwargs)#
post(request)#

Submit photos for verification.

This end-point is used for the following cases:

  • Initial verification through the pay-and-verify flow.

  • Initial verification initiated from a checkpoint within a course.

  • Re-verification initiated from a checkpoint within a course.

POST Parameters:

face_image (str): base64-encoded image data of the user’s face. photo_id_image (str): base64-encoded image data of the user’s photo ID. full_name (str): The user’s full name, if the user is requesting a name change as well.

class lms.djangoapps.verify_student.views.VerificationStatusAPIView(**kwargs)#

Bases: APIView

GET /verify_student/status/

Parameters: None

Returns:

200 OK {

”status”: String, “expires”: String, “can_verify”: Boolean

}

Notes

  • “status” is a verification status string, or “none” if there is none.

  • Verification should be allowed if and only if “can_verify” is true.

  • If there is a current verification, then “expires” is a ISO datetime string.

  • Otherwise, “expires” is omitted.

get(request)#

Handle the GET request.

lms.djangoapps.verify_student.views.checkout_with_ecommerce_service(user, course_key, course_mode, processor)#

Create a new basket and trigger immediate checkout, using the E-Commerce API.

lms.djangoapps.verify_student.views.create_order(request)#

This endpoint is named ‘create_order’ for backward compatibility, but its actual use is to add a single product to the user’s cart and request immediate checkout.

lms.djangoapps.verify_student.views.results_callback(request)#

Software Secure will call this callback to tell us whether a user is verified to be who they said they are.

Module contents#

Student Identity Verification App