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

strust identities #131

Merged
merged 4 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion doc/commands/strust.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ Creates a new (or replaces an existing) STRUST Identity. The description will be
language settings.

```bash
sapcli strust createidentity [-i|--identity IDENTITY] [-s|--storage STORAGE] [-d|--description DESCRIPTION] [--overwrite]
sapcli strust createidentity [-i|--identity IDENTITY] [-s|--storage STORAGE] [-d|--description DESCRIPTION] [-l|--language-iso-code LANG-ISO-639] [--overwrite]
```

**Parameters**:
- `--identity`: STRUST identity (PSE context + PSE application). **(Mutually exclusive with the option --storage)**
- `--storage`: Predefined STRUST identities. **(Mutually exclusive with the option --identity)**
- `--description`: Identity Description. **(optional)**
- `--language-iso-code`: Language of Identity Description - if not given, the language will be deduced from the current system locale. **(optional)**
- `--overwrite`: Overwrite the existing Identity, default is `False`. **(optional)**

# getcsr
Expand Down
5 changes: 4 additions & 1 deletion sap/cli/strust.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ def _get_ssl_storage_from_args(connection, args):
connection,
identity.pse_context,
identity.pse_applic,
description=getattr(args, 'description', None)
description=getattr(args, 'description', None),
lang_iso_code=getattr(args, 'language_iso_code', None)
)


Expand Down Expand Up @@ -144,6 +145,8 @@ def createpse(connection, args):
return 0


@CommandGroup.argument('-l', '--language-iso-code', type=str,
help='ISO code of language of Identity description (default: the current system locale')
@CommandGroup.argument('-d', '--description', type=str, help='Identity description')
@CommandGroup.argument('--overwrite', help='Overwrite the existing STRUST Identity', action='store_true', default=False)
@CommandGroup.argument('-s', '--storage', default=None, help='Mutually exclusive with the option -i',
Expand Down
21 changes: 21 additions & 0 deletions sap/platform/language.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""ABAP Platform helpers and utilities"""

from locale import getlocale

from sap.errors import SAPCliError

# Supported Languages and Code Pages (Non-Unicode)
Expand Down Expand Up @@ -66,8 +68,27 @@ def sap_code_to_iso_code(sap_code: str) -> str:
def iso_code_to_sap_code(iso_code: str) -> str:
"""Coverts ISO codes to one letter SAP language codes"""

iso_code = iso_code.upper()
try:
return next((entry[1] for entry in CODE_LIST if entry[0] == iso_code))
except StopIteration:
# pylint: disable=raise-missing-from
raise SAPCliError(f'Not found ISO Code: {iso_code}')


def locale_lang_sap_code() -> str:
"""Reads current system locale and attempts to convert the language part
to SAP Language Code
"""

loc = getlocale()
lang = loc[0] or ""

if len(lang) < 2:
raise SAPCliError(f'The current system locale language is not ISO 3166: {lang}')

try:
return iso_code_to_sap_code(lang[0:2].upper())
except SAPCliError as ex:
raise SAPCliError(
f'The current system locale language cannot be converted to SAP language code: {lang}') from ex
18 changes: 12 additions & 6 deletions sap/rfc/strust.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""SAP STRUST utilities"""

from sap.platform.language import iso_code_to_sap_code
from sap.platform.language import (
iso_code_to_sap_code,
locale_lang_sap_code
)
from sap.rfc.bapi import (
BAPIReturn,
BAPIError
Expand Down Expand Up @@ -121,12 +124,15 @@ def __init__(self, connection, pse_context, pse_applic, description=None, lang_i
'PSE_APPLIC': pse_applic
}

self.description = {
'PSE_DESCRIPT': description
}
self.description = {}

if description is not None:
self.description['PSE_DESCRIPT'] = description

if lang_iso_code:
self.description['SPRSL'] = iso_code_to_sap_code(lang_iso_code)
if lang_iso_code:
self.description['SPRSL'] = iso_code_to_sap_code(lang_iso_code)
else:
self.description['SPRSL'] = locale_lang_sap_code()

def __repr__(self):
return 'SSL Storage {PSE_CONTEXT}/{PSE_APPLIC}'.format(**self.identity)
Expand Down
37 changes: 34 additions & 3 deletions test/unit/test_sap_cli_strust.py
Original file line number Diff line number Diff line change
Expand Up @@ -1049,48 +1049,79 @@ def createidentity(self, *test_args):
def test_createidentity_with_storage_ok(self):
self.mock_connection.call.return_value = {'ET_BAPIRET2':[]}

self.createidentity('-s', 'server_standard', '--description', 'Identity Description')
self.createidentity(
'-s', 'server_standard',
'--description', 'Identity Description',
'-l', 'zh')

self.mock_connection.call.assert_called_once_with(
'SSFR_IDENTITY_CREATE',
IS_STRUST_IDENTITY={
'PSE_CONTEXT': 'SSLS',
'PSE_APPLIC': 'DFAULT',
'PSE_DESCRIPT': 'Identity Description',
'SPRSL': '1',
},
IV_REPLACE_EXISTING_APPL='-',
)

def test_createidentity_with_identity_ok(self):
self.mock_connection.call.return_value = {'ET_BAPIRET2':[]}

self.createidentity('-i', 'SSLC/100_SD', '--description', 'Identity Description')
self.createidentity(
'-i', 'SSLC/100_SD',
'--description', 'Identity Description',
'-l', 'zh')

self.mock_connection.call.assert_called_once_with(
'SSFR_IDENTITY_CREATE',
IS_STRUST_IDENTITY={
'PSE_CONTEXT': 'SSLC',
'PSE_APPLIC': '100_SD',
'PSE_DESCRIPT': 'Identity Description',
'SPRSL': '1',
},
IV_REPLACE_EXISTING_APPL='-',
)

def test_createidentity_with_replace_ok(self):
self.mock_connection.call.return_value = {'ET_BAPIRET2':[]}

self.createidentity('-s', 'server_standard', '--description', 'Identity Description', '--overwrite')
self.createidentity(
'-s', 'server_standard',
'--description', 'Identity Description',
'--language-iso-code', 'zh',
'--overwrite')

self.mock_connection.call.assert_called_once_with(
'SSFR_IDENTITY_CREATE',
IS_STRUST_IDENTITY={
'PSE_CONTEXT': 'SSLS',
'PSE_APPLIC': 'DFAULT',
'PSE_DESCRIPT': 'Identity Description',
'SPRSL': '1',
},
IV_REPLACE_EXISTING_APPL='X',
)

def test_createidentity_with_language_from_locale(self):
self.mock_connection.call.return_value = {'ET_BAPIRET2':[]}

with patch('sap.platform.language.getlocale', return_value=('zh_CN', 'UTF-8')):
self.createidentity(
'-s', 'server_standard',
'--description', 'Identity Description')

self.mock_connection.call.assert_called_once_with(
'SSFR_IDENTITY_CREATE',
IS_STRUST_IDENTITY={
'PSE_CONTEXT': 'SSLS',
'PSE_APPLIC': 'DFAULT',
'PSE_DESCRIPT': 'Identity Description',
'SPRSL': '1',
},
IV_REPLACE_EXISTING_APPL='-',
)

if __name__ == '__main__':
unittest.main()
39 changes: 39 additions & 0 deletions test/unit/test_sap_platform_language.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

import unittest
from unittest.mock import patch

import sap.errors
import sap.platform.language
Expand All @@ -20,12 +21,50 @@ def test_sap_code_to_iso_code_not_found(self):
def test_iso_code_to_sap_code_ok(self):
self.assertEqual(sap.platform.language.iso_code_to_sap_code('EN'), 'E')

def test_iso_code_to_sap_code_lower_ok(self):
self.assertEqual(sap.platform.language.iso_code_to_sap_code('en'), 'E')

def test_iso_code_to_sap_code_not_found(self):
with self.assertRaises(sap.errors.SAPCliError) as raised:
sap.platform.language.iso_code_to_sap_code('#')

self.assertEqual(str(raised.exception), 'Not found ISO Code: #')


class TestSAPPlatformLanguageLocale(unittest.TestCase):

def test_locale_lang_to_sap_code_ok(self):
with patch('sap.platform.language.getlocale', return_value=('en_US', 'UTF-8')):
sap_lang = sap.platform.language.locale_lang_sap_code()

self.assertEqual(sap_lang, 'E')

def test_locale_lang_to_sap_code_C(self):
"""This is a special case for a short case because C is kinda special
as it is the POSIX portable locale and we may want to handle it
differently in feature.
"""

with patch('sap.platform.language.getlocale', return_value=('C', 'UTF-8')):
with self.assertRaises(sap.errors.SAPCliError) as caught:
sap_lang = sap.platform.language.locale_lang_sap_code()

self.assertEqual(str(caught.exception), 'The current system locale language is not ISO 3166: C')

def test_locale_lang_to_sap_code_short(self):
with patch('sap.platform.language.getlocale', return_value=('e', 'UTF-8')):
with self.assertRaises(sap.errors.SAPCliError) as caught:
sap_lang = sap.platform.language.locale_lang_sap_code()

self.assertEqual(str(caught.exception), 'The current system locale language is not ISO 3166: e')

def test_locale_lang_to_sap_code_unknown(self):
with patch('sap.platform.language.getlocale', return_value=('WF', 'UTF-8')):
with self.assertRaises(sap.errors.SAPCliError) as caught:
sap_lang = sap.platform.language.locale_lang_sap_code()

self.assertEqual(str(caught.exception), 'The current system locale language cannot be converted to SAP language code: WF')


if __name__ == '__main__':
unittest.main()
14 changes: 12 additions & 2 deletions test/unit/test_sap_rfc_strust.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ def test_ctor(self):

self.assertEqual(self.ssl_storage.identity['PSE_CONTEXT'], self.pse_context)
self.assertEqual(self.ssl_storage.identity['PSE_APPLIC'], self.pse_applic)
self.assertEqual(self.ssl_storage.description['PSE_DESCRIPT'], None)
self.assertEqual(len(self.ssl_storage.description), 1)
self.assertEqual(len(self.ssl_storage.description), 0)

def test_ctor_with_description_and_lang(self):
self.assertIs(self.ssl_storage._connection, self.connection)
Expand All @@ -115,6 +114,17 @@ def test_ctor_with_description_and_lang(self):
self.assertEqual(self.ssl_storage.description['PSE_DESCRIPT'], self.pse_description)
self.assertEqual(self.ssl_storage.description['SPRSL'], '1')

def test_ctor_with_description_and_lang_from_locale(self):
with patch('sap.rfc.strust.locale_lang_sap_code', return_value='1') as fake_locale_lang_sap_code:
self.ssl_storage = SSLCertStorage(
self.connection,
self.pse_context,
self.pse_applic,
description=self.pse_description)

fake_locale_lang_sap_code.assert_called_once_with()
self.assertEqual(self.ssl_storage.description['SPRSL'], '1')

def test_repr(self):
self.assertEqual(repr(self.ssl_storage), f'SSL Storage {self.pse_context}/{self.pse_applic}')

Expand Down
Loading