diff --git a/physionet-django/user/forms.py b/physionet-django/user/forms.py
index 5ca6e18c13..5623866419 100644
--- a/physionet-django/user/forms.py
+++ b/physionet-django/user/forms.py
@@ -1,4 +1,5 @@
import datetime
+import json
import time
from django import forms
@@ -14,6 +15,11 @@
from django.utils.html import mark_safe
from django.utils.translation import gettext_lazy
from physionet.utility import validate_pdf_file_type
+from user.awsverification import (
+ AWSVerificationFailed,
+ get_aws_verification_command,
+ check_aws_verification_url,
+)
from user.models import (
AssociatedEmail,
CloudInformation,
@@ -28,8 +34,14 @@
)
from user.trainingreport import TrainingCertificateError, find_training_report_url
from user.userfiles import UserFiles
-from user.validators import UsernameValidator, validate_name, validate_training_file_size
-from user.validators import validate_institutional_email
+from user.validators import (
+ UsernameValidator,
+ validate_aws_id,
+ validate_aws_userid,
+ validate_institutional_email,
+ validate_name,
+ validate_training_file_size,
+)
from user.widgets import ProfilePhotoInput
from django.db.models import OuterRef, Exists
@@ -675,10 +687,9 @@ class CloudForm(forms.ModelForm):
"""
class Meta:
model = CloudInformation
- fields = ('gcp_email','aws_id',)
+ fields = ('gcp_email',)
labels = {
'gcp_email': 'Google (Email)',
- 'aws_id': 'Amazon (ID)',
}
def __init__(self, *args, **kwargs):
# Email choices are those belonging to a user
@@ -688,6 +699,79 @@ def __init__(self, *args, **kwargs):
self.fields['gcp_email'].required = False
+class AWSIdentityForm(forms.Form):
+ aws_identity = forms.CharField(
+ label="Caller identity", max_length=2000,
+ widget=forms.Textarea(attrs={
+ 'rows': 5,
+ 'placeholder': '{"UserId": "...", "Account": "...", "Arn": "..."}'
+ })
+ )
+
+ def clean(self):
+ try:
+ identity = super().clean()['aws_identity']
+ data = json.loads(identity)
+ aws_account = data['Account']
+ aws_userid = data['UserId']
+ except (TypeError, KeyError, ValueError):
+ raise forms.ValidationError(
+ mark_safe("Copy and paste the output of the "
+ "aws sts get-caller-identity
command."))
+ validate_aws_id(aws_account)
+ validate_aws_userid(aws_userid)
+ return {
+ 'aws_account': aws_account,
+ 'aws_userid': aws_userid
+ }
+
+
+class AWSVerificationForm(forms.Form):
+ signed_url = forms.CharField(
+ label="Signed URL", max_length=2000,
+ widget=forms.Textarea(attrs={
+ 'rows': 6,
+ 'placeholder': 'https://...'
+ })
+ )
+
+ def __init__(self, user, site_domain, aws_account, aws_userid,
+ **kwargs):
+ super().__init__(**kwargs)
+ self.user = user
+ self.site_domain = site_domain
+ self.aws_account = aws_account
+ self.aws_userid = aws_userid
+
+ def aws_verification_command(self):
+ return get_aws_verification_command(site_domain=self.site_domain,
+ user_email=self.user.email,
+ aws_account=self.aws_account,
+ aws_userid=self.aws_userid)
+
+ def clean(self):
+ data = super().clean()
+ signed_url = data['signed_url'].strip()
+ try:
+ info = check_aws_verification_url(site_domain=self.site_domain,
+ user_email=self.user.email,
+ signed_url=signed_url)
+ except AWSVerificationFailed:
+ raise forms.ValidationError("Invalid verification URL")
+
+ validate_aws_id(info['account'])
+ validate_aws_userid(info['userid'])
+ data.update(info)
+ return data
+
+ def save(self):
+ cloud_info = CloudInformation.objects.get_or_create(user=self.user)[0]
+ cloud_info.aws_id = self.cleaned_data['account']
+ cloud_info.aws_userid = self.cleaned_data['userid']
+ cloud_info.aws_verification_datetime = timezone.now()
+ cloud_info.save()
+
+
# class ActivationForm(forms.ModelForm):
class ActivationForm(forms.Form):
"""A form for creating new users. Includes all the required
diff --git a/physionet-django/user/templates/user/edit_cloud.html b/physionet-django/user/templates/user/edit_cloud.html
index 9056e0eb40..0928da94e5 100644
--- a/physionet-django/user/templates/user/edit_cloud.html
+++ b/physionet-django/user/templates/user/edit_cloud.html
@@ -12,12 +12,58 @@