Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unencrypted sap client credentials #2217

Merged
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
c0d2965
feat: added encrypted columns for user credentials for SAP config
MueezKhan246 Aug 22, 2024
e9fd79f
refactor: updated build version
MueezKhan246 Aug 22, 2024
64302e4
refactor: added necessary blank space
MueezKhan246 Aug 22, 2024
04c1c29
feat: added migration's file
MueezKhan246 Aug 23, 2024
99e2759
refactor: removed setters and getters for scope of release
MueezKhan246 Aug 23, 2024
c7bffcf
refactor: removed redundant imports
MueezKhan246 Aug 23, 2024
c5d2d2f
feat: added signal for updating encrypted columns
MueezKhan246 Aug 23, 2024
891f85d
refactor: added getters for encrypted credentials
MueezKhan246 Aug 23, 2024
84b3331
refactor: diasabled warning for unused argument
MueezKhan246 Aug 23, 2024
12d07d6
test: added test for setter and getters
MueezKhan246 Aug 23, 2024
8e56778
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Aug 26, 2024
e91eac7
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Aug 26, 2024
240f55e
feat: added data migration to populate encrypted columns
MueezKhan246 Aug 26, 2024
6fa445b
feat: replaced references from unencrypted to encrypted columns
MueezKhan246 Aug 26, 2024
f9b8900
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Aug 26, 2024
b9d1098
refactor: updated build version
MueezKhan246 Aug 26, 2024
fd25199
test: fixing tests failed because of factory error
MueezKhan246 Aug 26, 2024
5ebf636
refactor: removed redundant signal
MueezKhan246 Aug 26, 2024
efd616d
feat: added migration make key nullable to fix failing tests
MueezKhan246 Aug 27, 2024
b0ffbb8
refactor: added necessary blankspace
MueezKhan246 Aug 27, 2024
c689eb2
test: fixed got unexpected keyword arguments "key"
MueezKhan246 Aug 27, 2024
c7bdb1a
test: added test for data migration
MueezKhan246 Aug 27, 2024
341d8c2
test: updated test_populate_decrypted_fields
MueezKhan246 Aug 27, 2024
13a9043
feat: added migration for removing unencrypted client credentials
MueezKhan246 Aug 27, 2024
32bd53a
refactor: update build version
MueezKhan246 Aug 27, 2024
80985f4
refactor: added feature flag for testing api client
MueezKhan246 Aug 28, 2024
135cf85
Merge branch 'MueezKhan/Data-Migration-For-Encrypted-Credentials-Colu…
MueezKhan246 Aug 28, 2024
60cbe4a
refactor: fixed attribute key error
MueezKhan246 Aug 28, 2024
db2b7af
refactor: removing feature flag
MueezKhan246 Aug 28, 2024
2cea266
refactor: kept unencrypted columns in model file
MueezKhan246 Aug 28, 2024
3d00290
refactor: added null=true for unencrypted columns in model
MueezKhan246 Aug 28, 2024
7ff82d9
feat: altered decrypted_secret to be encrypted and made credentials n…
MueezKhan246 Aug 29, 2024
d915377
refactor: updated build version
MueezKhan246 Aug 29, 2024
9e5279f
Merge branch 'MueezKhan/Altering-Client-ID-And-Secret-In-SAP-Configur…
MueezKhan246 Aug 29, 2024
86ad20b
refactor: removed redundant migrations
MueezKhan246 Aug 29, 2024
e65ae31
refactor: removed unencrypted credentials from sap config model
MueezKhan246 Aug 29, 2024
7718973
refactor: updated build version
MueezKhan246 Aug 29, 2024
f8ce96f
Merge branch 'MueezKhan/Removing-Unencrypted-Credentials-From-Model' …
MueezKhan246 Aug 29, 2024
d9436b4
refactor: updated migration dependency
MueezKhan246 Aug 29, 2024
0b7b125
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Aug 30, 2024
abfb873
refactor: updated build version
MueezKhan246 Aug 30, 2024
40ae2b3
feat: removed char field decrypted_secret from code
MueezKhan246 Sep 3, 2024
ae5805c
refactor: update build version
MueezKhan246 Sep 3, 2024
5e74c43
refactor: updated log entry in changelog file
MueezKhan246 Sep 4, 2024
8c9d92f
Merge branch 'MueezKhan/Removing-Decrypted-Client-Secret-In-SAP-Confi…
MueezKhan246 Sep 4, 2024
8d781d7
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 4, 2024
0524bab
refactor: update build version in init file
MueezKhan246 Sep 4, 2024
e4b1b77
Merge branch 'MueezKhan/Removing-Decrypted-Client-Secret-In-SAP-Confi…
MueezKhan246 Sep 4, 2024
0ec1199
feat: added migration file for removing char field decrypted_secret
MueezKhan246 Sep 4, 2024
f200ebe
refactor: updated build version
MueezKhan246 Sep 4, 2024
3bb3b5d
feat: added encrypted client secret for SAP config
MueezKhan246 Sep 4, 2024
b5cc335
refactor: updated build version
MueezKhan246 Sep 4, 2024
0ddfe45
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 6, 2024
d61dbff
refactor: removed redundant trailing whitespace
MueezKhan246 Sep 6, 2024
094bceb
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 6, 2024
4632897
Merge branch 'MueezKhan/Added-Encrypted-Client-Secret-In-SAP-Configur…
MueezKhan246 Sep 6, 2024
b358f88
refactor: removed signal as all references are needed to be removed
MueezKhan246 Sep 6, 2024
e04f50f
refactor: resolved conflicting migrations
MueezKhan246 Sep 6, 2024
c344bdf
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 9, 2024
81671b6
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 9, 2024
850484f
Merge branch 'MueezKhan/Data-Migration-For-Encrypted-Credentials-Colu…
MueezKhan246 Sep 9, 2024
ee0412c
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 9, 2024
7c580e9
Merge branch 'MueezKhan/Removing-Unencrypted-Credentials-From-Model' …
MueezKhan246 Sep 9, 2024
6ad773a
refactor: making unencrypted credentials nullable so after removing r…
MueezKhan246 Sep 9, 2024
82cfbe6
refactor: update build version
MueezKhan246 Sep 9, 2024
b913b3c
Merge branch 'MueezKhan/Making-Unencrypted-SAP-Client-Credentials-Nul…
MueezKhan246 Sep 9, 2024
819f201
Merge branch 'MueezKhan/Removing-Unencrypted-Credentials-From-Model' …
MueezKhan246 Sep 9, 2024
b8c71de
refactor: fixed migrations conflict issue
MueezKhan246 Sep 9, 2024
f46067c
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 10, 2024
b2ea600
Merge branch 'MueezKhan/Making-Unencrypted-SAP-Client-Credentials-Nul…
MueezKhan246 Sep 10, 2024
d2a0a89
Merge branch 'MueezKhan/Removing-Unencrypted-Credentials-From-Model' …
MueezKhan246 Sep 10, 2024
261c873
Merge branch 'master' of github.com:openedx/edx-enterprise into Mueez…
MueezKhan246 Sep 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ Unreleased
----------
* nothing unreleased

[4.23.17]
----------
* feat: added migration for removing unencrypted client credentials

[4.23.16]
----------
* refactor: removed unencrypted credentials from sap config model

[4.23.15]
----------
* feat: replaced references from unencrypted to encrypted columns
* feat: added data migration to populate encrypted columns

[4.23.14]
----------
* feat: altered decrypted_secret to be encrypted and made credentials nullable

[4.23.13]
----------
* feat: added encrypted columns for user credentials for SAP config
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "4.23.13"
__version__ = "4.23.17"
11 changes: 0 additions & 11 deletions enterprise/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,14 +475,3 @@ def mirror_id_and_secret_to_decrypted_fields(sender, instance, **kwargs): # py

if COURSE_ENROLLMENT_CHANGED is not None:
COURSE_ENROLLMENT_CHANGED.connect(course_enrollment_changed_receiver)


@receiver(pre_save, sender=SAPSuccessFactorsEnterpriseCustomerConfiguration)
def update_decrypted_credentials(sender, instance, **kwargs): # pylint: disable=unused-argument
"""
Ensure that the decrypted credentials have same values as unencrypted credentials.
"""
if instance.key != instance.decrypted_key:
instance.decrypted_key = instance.key
if instance.secret != instance.decrypted_secret:
instance.decrypted_secret = instance.secret
9 changes: 7 additions & 2 deletions integrated_channels/api/v1/sap_success_factors/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Serializer for Success Factors configuration.
"""
from rest_framework import serializers

from integrated_channels.api.serializers import EnterpriseCustomerPluginConfigSerializer
from integrated_channels.sap_success_factors.models import SAPSuccessFactorsEnterpriseCustomerConfiguration

Expand All @@ -9,15 +11,18 @@ class SAPSuccessFactorsConfigSerializer(EnterpriseCustomerPluginConfigSerializer
class Meta:
model = SAPSuccessFactorsEnterpriseCustomerConfiguration
extra_fields = (
'key',
'encrypted_key',
'sapsf_base_url',
'sapsf_company_id',
'sapsf_user_id',
'secret',
'encrypted_secret',
'user_type',
'additional_locales',
'show_course_price',
'transmit_total_hours',
'prevent_self_submit_grades',
)
fields = EnterpriseCustomerPluginConfigSerializer.Meta.fields + extra_fields

encrypted_key = serializers.CharField(required=False, allow_blank=False, read_only=False)
encrypted_secret = serializers.CharField(required=False, allow_blank=False, read_only=False)
6 changes: 2 additions & 4 deletions integrated_channels/sap_success_factors/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ class SAPSuccessFactorsEnterpriseCustomerConfigurationAdmin(DjangoObjectActions,
"active",
"sapsf_base_url",
"sapsf_company_id",
"key",
"decrypted_key",
"secret",
"decrypted_secret",
"sapsf_user_id",
"user_type",
Expand Down Expand Up @@ -111,8 +109,8 @@ def has_access_token(self, obj):
try:
access_token, expires_at = SAPSuccessFactorsAPIClient.get_oauth_access_token(
obj.sapsf_base_url,
obj.key,
obj.secret,
obj.decrypted_key,
obj.decrypted_secret,
obj.sapsf_company_id,
obj.sapsf_user_id,
obj.user_type,
Expand Down
8 changes: 4 additions & 4 deletions integrated_channels/sap_success_factors/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ def _create_session(self):
self.session.close()

oauth_access_token, expires_at = self.get_oauth_access_token(
self.enterprise_configuration.key,
self.enterprise_configuration.secret,
self.enterprise_configuration.decrypted_key,
self.enterprise_configuration.decrypted_secret,
self.enterprise_configuration.sapsf_company_id,
self.enterprise_configuration.sapsf_user_id,
self.enterprise_configuration.user_type,
Expand Down Expand Up @@ -301,8 +301,8 @@ def _call_post_with_user_override(self, sap_user_id, url, payload):
'SAPSuccessFactorsEnterpriseCustomerConfiguration'
)
oauth_access_token, _ = self.get_oauth_access_token(
self.enterprise_configuration.key,
self.enterprise_configuration.secret,
self.enterprise_configuration.decrypted_key,
self.enterprise_configuration.decrypted_secret,
self.enterprise_configuration.sapsf_company_id,
sap_user_id,
SAPSuccessFactorsEnterpriseCustomerConfiguration.USER_TYPE_USER,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 3.2.23 on 2024-08-29 09:10

from django.db import migrations, models
import fernet_fields.fields


class Migration(migrations.Migration):

dependencies = [
('sap_success_factors', '0017_auto_20240823_0936'),
]

operations = [
migrations.AlterField(
model_name='sapsuccessfactorsenterprisecustomerconfiguration',
name='decrypted_secret',
field=fernet_fields.fields.EncryptedCharField(blank=True, default='', help_text='The encrypted OAuth client secret. It will be encrypted when stored in the database.', max_length=255, null=True, verbose_name='Encrypted Client Secret'),
),
migrations.AlterField(
model_name='sapsuccessfactorsenterprisecustomerconfiguration',
name='key',
field=models.CharField(blank=True, default='', help_text='OAuth client identifier.', max_length=255, null=True, verbose_name='Client ID'),
),
migrations.AlterField(
model_name='sapsuccessfactorsenterprisecustomerconfiguration',
name='secret',
field=models.CharField(blank=True, default='', help_text='OAuth client secret.', max_length=255, null=True, verbose_name='Client Secret'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Generated by Django 3.2.23 on 2024-08-26 09:54

from django.db import migrations
from integrated_channels.sap_success_factors.utils import populate_decrypted_fields_sap_success_factors


class Migration(migrations.Migration):

dependencies = [
('sap_success_factors', '0018_auto_20240829_0910'),
]

operations = [
migrations.RunPython(populate_decrypted_fields_sap_success_factors, reverse_code=migrations.RunPython.noop),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.23 on 2024-08-27 12:38

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('sap_success_factors', '0019_auto_20240829_1044'),
]

operations = [
migrations.RemoveField(
model_name='sapsuccessfactorsenterprisecustomerconfiguration',
name='key',
),
migrations.RemoveField(
model_name='sapsuccessfactorsenterprisecustomerconfiguration',
name='secret',
),
]
66 changes: 48 additions & 18 deletions integrated_channels/sap_success_factors/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from fernet_fields import EncryptedCharField

from django.db import models
from django.utils.encoding import force_bytes, force_str
from django.utils.translation import gettext_lazy as _

from integrated_channels.exceptions import ClientError
Expand Down Expand Up @@ -74,14 +75,6 @@ class SAPSuccessFactorsEnterpriseCustomerConfiguration(EnterpriseCustomerPluginC
(USER_TYPE_ADMIN, 'Admin'),
)

key = models.CharField(
max_length=255,
blank=True,
default='',
verbose_name="Client ID",
help_text=_("OAuth client identifier.")
)

decrypted_key = EncryptedCharField(
max_length=255,
verbose_name="Encrypted Client ID",
Expand All @@ -94,6 +87,28 @@ class SAPSuccessFactorsEnterpriseCustomerConfiguration(EnterpriseCustomerPluginC
null=True
)

@property
def encrypted_key(self):
"""
Return encrypted key as a string.
The data is encrypted in the DB at rest, but is unencrypted in the app when retrieved through the
decrypted_key field. This method will encrypt the key again before sending.
"""
if self.decrypted_key:
return force_str(
self._meta.get_field('decrypted_key').fernet.encrypt(
force_bytes(self.decrypted_key)
)
)
return self.decrypted_key

@encrypted_key.setter
def encrypted_key(self, value):
"""
Set the encrypted key.
"""
self.decrypted_key = value

sapsf_base_url = models.CharField(
max_length=255,
blank=True,
Expand All @@ -115,15 +130,8 @@ class SAPSuccessFactorsEnterpriseCustomerConfiguration(EnterpriseCustomerPluginC
verbose_name="SAP User ID",
help_text=_("Success factors user identifier.")
)
secret = models.CharField(
max_length=255,
blank=True,
default='',
verbose_name="Client Secret",
help_text=_("OAuth client secret.")
)

decrypted_secret = models.CharField(
decrypted_secret = EncryptedCharField(
max_length=255,
blank=True,
default='',
Expand All @@ -135,6 +143,28 @@ class SAPSuccessFactorsEnterpriseCustomerConfiguration(EnterpriseCustomerPluginC
null=True
)

@property
def encrypted_secret(self):
"""
Return encrypted secret as a string.
The data is encrypted in the DB at rest, but is unencrypted in the app when retrieved through the
decrypted_secret field. This method will encrypt the secret again before sending.
"""
if self.decrypted_secret:
return force_str(
self._meta.get_field('decrypted_secret').fernet.encrypt(
force_bytes(self.decrypted_secret)
)
)
return self.decrypted_secret

@encrypted_secret.setter
def encrypted_secret(self, value):
"""
Set the encrypted secret.
"""
self.decrypted_secret = value

user_type = models.CharField(
max_length=20,
choices=USER_TYPE_CHOICES,
Expand Down Expand Up @@ -205,15 +235,15 @@ def is_valid(self):
"""
missing_items = {'missing': []}
incorrect_items = {'incorrect': []}
if not self.key:
if not self.decrypted_key:
missing_items.get('missing').append('key')
if not self.sapsf_base_url:
missing_items.get('missing').append('sapsf_base_url')
if not self.sapsf_company_id:
missing_items.get('missing').append('sapsf_company_id')
if not self.sapsf_user_id:
missing_items.get('missing').append('sapsf_user_id')
if not self.secret:
if not self.decrypted_secret:
missing_items.get('missing').append('secret')
if not is_valid_url(self.sapsf_base_url):
incorrect_items.get('incorrect').append('sapsf_base_url')
Expand Down
19 changes: 19 additions & 0 deletions integrated_channels/sap_success_factors/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Utilities for SAP Success Factors integrated channel.
"""


def populate_decrypted_fields_sap_success_factors(apps, schema_editor=None): # pylint: disable=unused-argument
"""
Populates the encryption fields in SAP Success Factors config with the data previously stored in database.
"""
SAPSuccessFactorsEnterpriseCustomerConfiguration = apps.get_model(
'sap_success_factors', 'SAPSuccessFactorsEnterpriseCustomerConfiguration'
)

for sap_success_factors_enterprise_configuration in SAPSuccessFactorsEnterpriseCustomerConfiguration.objects.all():
sap_success_factors_enterprise_configuration.decrypted_key = getattr(
sap_success_factors_enterprise_configuration, 'key', '')
sap_success_factors_enterprise_configuration.decrypted_secret = getattr(
sap_success_factors_enterprise_configuration, 'secret', '')
sap_success_factors_enterprise_configuration.save()
Loading