Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
6027e5fc
Commit
6027e5fc
authored
Nov 06, 2017
by
Matt Drayer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mattdrayer/ENT-686: Enhanced logging for SuccessFactors exceptions
parent
80cf046d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
117 additions
and
66 deletions
+117
-66
common/djangoapps/third_party_auth/saml.py
+115
-64
common/djangoapps/third_party_auth/tests/specs/test_testshib.py
+2
-2
No files found.
common/djangoapps/third_party_auth/saml.py
View file @
6027e5fc
...
...
@@ -231,10 +231,10 @@ class SapSuccessFactorsIdentityProvider(EdXSAMLIdentityProvider):
def
odata_client_id
(
self
):
return
self
.
conf
[
'odata_client_id'
]
def
missing_variables
(
self
):
def
invalid_configuration
(
self
):
"""
Check that we have all the details we need to properly retrieve rich data from the
SAP SuccessFactors OData API. If we don't, then we should log a warning indicating
SAP SuccessFactors
BizX
OData API. If we don't, then we should log a warning indicating
the specific variables that are missing.
"""
if
not
all
(
var
in
self
.
conf
for
var
in
self
.
required_variables
):
...
...
@@ -246,85 +246,136 @@ class SapSuccessFactorsIdentityProvider(EdXSAMLIdentityProvider):
)
return
missing
def
get_odata_api_client
(
self
,
user_id
):
def
log_bizx_api_exception
(
self
,
transaction_data
,
err
):
sys_msg
=
err
.
response
.
json
()
if
err
.
response
else
'Not available'
headers
=
err
.
response
.
headers
if
err
.
response
else
'Not available'
token_data
=
transaction_data
.
get
(
'token_data'
)
token_data
=
token_data
if
token_data
else
'Not available'
log_msg_template
=
(
'SAPSuccessFactors exception received for {operation_name} request. '
+
'URL: {url} '
+
'Company ID: {company_id}. '
+
'User ID: {user_id}. '
+
'Error message: {err_msg}. '
+
'System message: {sys_msg}. '
+
'Headers: {headers}. '
+
'Token Data: {token_data}.'
)
log_msg
=
log_msg_template
.
format
(
operation_name
=
transaction_data
[
'operation_name'
],
url
=
transaction_data
[
'endpoint_url'
],
company_id
=
transaction_data
[
'company_id'
],
user_id
=
transaction_data
[
'user_id'
],
err_msg
=
err
.
message
,
sys_msg
=
sys_msg
,
headers
=
headers
,
token_data
=
token_data
,
)
log
.
warning
(
log_msg
,
exc_info
=
True
)
def
generate_bizx_oauth_api_saml_assertion
(
self
,
user_id
):
"""
Get a Requests session with the headers needed to properly authenticate it with
the SAP SuccessFactors OData API
.
Obtain a SAML assertion from the SAP SuccessFactors BizX OAuth2 identity provider service using
information specified in the third party authentication configuration "Advanced Settings" section
.
"""
session
=
requests
.
Session
()
assertion
=
session
.
post
(
self
.
sapsf_idp_url
,
data
=
{
'client_id'
:
self
.
odata_client_id
,
'user_id'
:
user_id
,
'token_url'
:
self
.
sapsf_token_url
,
'private_key'
:
self
.
sapsf_private_key
,
},
timeout
=
self
.
timeout
,
)
assertion
.
raise_for_status
()
assertion
=
assertion
.
text
token
=
session
.
post
(
self
.
sapsf_token_url
,
data
=
{
'client_id'
:
self
.
odata_client_id
,
'company_id'
:
self
.
odata_company_id
,
'grant_type'
:
'urn:ietf:params:oauth:grant-type:saml2-bearer'
,
'assertion'
:
assertion
,
},
timeout
=
self
.
timeout
,
)
token
.
raise_for_status
()
token
=
token
.
json
()[
'access_token'
]
session
.
headers
.
update
({
'Authorization'
:
'Bearer {}'
.
format
(
token
),
'Accept'
:
'application/json'
})
transaction_data
=
{
'operation_name'
:
'generate_bizx_oauth_api_saml_assertion'
,
'endpoint_url'
:
self
.
sapsf_idp_url
,
'token_url'
:
self
.
sapsf_token_url
,
'company_id'
:
self
.
odata_company_id
,
'client_id'
:
self
.
odata_client_id
,
'user_id'
:
user_id
,
'private_key'
:
self
.
sapsf_private_key
,
}
try
:
assertion
=
session
.
post
(
transaction_data
[
'endpoint_url'
],
data
=
transaction_data
,
timeout
=
self
.
timeout
,
)
assertion
.
raise_for_status
()
except
requests
.
RequestException
as
err
:
self
.
log_bizx_api_exception
(
transaction_data
,
err
)
return
None
return
assertion
.
text
def
generate_bizx_oauth_api_access_token
(
self
,
user_id
):
"""
Request a new access token from the SuccessFactors BizX OAuth2 identity provider service
using a valid SAML assertion (see generate_bizx_api_saml_assertion) and the infomration specified
in the third party authentication configuration "Advanced Settings" section.
"""
session
=
requests
.
Session
()
transaction_data
=
{
'operation_name'
:
'generate_bizx_oauth_api_access_token'
,
'endpoint_url'
:
self
.
sapsf_token_url
,
'client_id'
:
self
.
odata_client_id
,
'company_id'
:
self
.
odata_company_id
,
'grant_type'
:
'urn:ietf:params:oauth:grant-type:saml2-bearer'
,
}
assertion
=
self
.
generate_bizx_oauth_api_saml_assertion
(
user_id
)
if
not
assertion
:
return
None
try
:
transaction_data
[
'assertion'
]
=
assertion
token_response
=
session
.
post
(
transaction_data
[
'endpoint_url'
],
data
=
transaction_data
,
timeout
=
self
.
timeout
,
)
token_response
.
raise_for_status
()
except
requests
.
RequestException
as
err
:
self
.
log_bizx_api_exception
(
transaction_data
,
err
)
return
None
return
token_response
.
json
()
def
get_bizx_odata_api_client
(
self
,
user_id
):
session
=
requests
.
Session
()
access_token_data
=
self
.
generate_bizx_oauth_api_access_token
(
user_id
)
if
not
access_token_data
:
return
None
token_string
=
access_token_data
[
'access_token'
]
session
.
headers
.
update
({
'Authorization'
:
'Bearer {}'
.
format
(
token_string
),
'Accept'
:
'application/json'
})
session
.
token_data
=
access_token_data
return
session
def
get_user_details
(
self
,
attributes
):
"""
Attempt to get rich user details from the SAP SuccessFactors OData API. If we're missing any
of the
details we need to do that, fail nicely by returning the details we're able to extract
from just the SAML response and log a warning
.
of the
info we need to do that, or if the request triggers an exception, then fail nicely by
returning the basic user details we're able to extract from just the SAML response
.
"""
details
=
super
(
SapSuccessFactorsIdentityProvider
,
self
)
.
get_user_details
(
attributes
)
if
self
.
missing_variables
():
# If there aren't enough details to make the request, log a warning and return the details
# from the SAML assertion.
return
details
username
=
details
[
'username'
]
basic_details
=
super
(
SapSuccessFactorsIdentityProvider
,
self
)
.
get_user_details
(
attributes
)
if
self
.
invalid_configuration
():
return
basic_details
user_id
=
basic_details
[
'username'
]
fields
=
','
.
join
(
self
.
field_mappings
)
odata_api_url
=
'{root_url}User(userId=
\'
{user_id}
\'
)?$select={fields}'
.
format
(
root_url
=
self
.
odata_api_root_url
,
user_id
=
username
,
fields
=
fields
,
)
transaction_data
=
{
'operation_name'
:
'get_user_details'
,
'user_id'
:
user_id
,
'company_id'
:
self
.
odata_company_id
,
'fields'
:
fields
,
'endpoint_url'
:
'{root_url}User(userId=
\'
{user_id}
\'
)?$select={fields}'
.
format
(
root_url
=
self
.
odata_api_root_url
,
user_id
=
user_id
,
fields
=
fields
,
),
}
client
=
self
.
get_bizx_odata_api_client
(
user_id
=
transaction_data
[
'user_id'
])
if
not
client
:
return
basic_details
try
:
client
=
self
.
get_odata_api_client
(
user_id
=
username
)
transaction_data
[
'token_data'
]
=
client
.
token_data
response
=
client
.
get
(
odata_api_url
,
transaction_data
[
'endpoint_url'
]
,
timeout
=
self
.
timeout
,
)
response
.
raise_for_status
()
response
=
response
.
json
()
except
requests
.
RequestException
as
err
:
# If there was an HTTP level error, log the error and return the details from the SAML assertion.
sys_msg
=
err
.
response
.
json
()
if
err
.
response
else
"Not available"
headers
=
err
.
response
.
headers
if
err
.
response
else
"Not available"
log_msg_template
=
(
'Unable to retrieve user details with username {username} from SAPSuccessFactors for company '
+
'ID {company} with url "{url}". Error message: {err_msg}. System message: {sys_msg}. '
+
'Headers: {headers}'
)
log_msg
=
log_msg_template
.
format
(
username
=
username
,
company
=
self
.
odata_company_id
,
url
=
odata_api_url
,
err_msg
=
err
.
message
,
sys_msg
=
sys_msg
,
headers
=
headers
)
log
.
warning
(
log_msg
,
exc_info
=
True
)
return
details
self
.
log_bizx_api_exception
(
transaction_data
,
err
)
return
basic_details
return
self
.
get_registration_fields
(
response
)
...
...
common/djangoapps/third_party_auth/tests/specs/test_testshib.py
View file @
6027e5fc
...
...
@@ -504,7 +504,7 @@ class SuccessFactorsIntegrationTest(SamlIntegrationTestUtilities, IntegrationTes
odata_company_id
=
'NCC1701D'
odata_api_root_url
=
'http://api.successfactors.com/odata/v2/'
mocked_odata_ai_url
=
self
.
_mock_odata_api_for_error
(
odata_api_root_url
,
self
.
USER_USERNAME
)
mocked_odata_a
p
i_url
=
self
.
_mock_odata_api_for_error
(
odata_api_root_url
,
self
.
USER_USERNAME
)
self
.
_configure_testshib_provider
(
identity_provider_type
=
'sap_success_factors'
,
metadata_source
=
TESTSHIB_METADATA_URL
,
...
...
@@ -520,7 +520,7 @@ class SuccessFactorsIntegrationTest(SamlIntegrationTestUtilities, IntegrationTes
super
(
SuccessFactorsIntegrationTest
,
self
)
.
test_register
()
logging_messages
=
str
([
log_msg
.
getMessage
()
for
log_msg
in
log_capture
.
records
])
.
replace
(
'
\\
'
,
''
)
self
.
assertIn
(
odata_company_id
,
logging_messages
)
self
.
assertIn
(
mocked_odata_ai_url
,
logging_messages
)
self
.
assertIn
(
mocked_odata_a
p
i_url
,
logging_messages
)
self
.
assertIn
(
self
.
USER_USERNAME
,
logging_messages
)
self
.
assertIn
(
"SAPSuccessFactors"
,
logging_messages
)
self
.
assertIn
(
"Error message"
,
logging_messages
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment