Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
139
Merge Requests
139
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
c64c0018
Commit
c64c0018
authored
2 years ago
by
Kazuhiko Shiozaki
Committed by
Arnaud Fontaine
7 months ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
py2/py3: import from six.moves.
parent
69142a8e
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
50 additions
and
52 deletions
+50
-52
bt5/erp5_oauth2_authorisation/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationServerConnector.py
...nents/document.erp5.OAuth2AuthorisationServerConnector.py
+14
-15
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_getClientIdFromLoginOnceCameFrom.py
...uthorisation/ERP5Site_getClientIdFromLoginOnceCameFrom.py
+2
-2
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_isOAuth2CameFrom.py
...ns/erp5_oauth2_authorisation/ERP5Site_isOAuth2CameFrom.py
+2
-2
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_retryOAuth2Authorisation.py
...oauth2_authorisation/ERP5Site_retryOAuth2Authorisation.py
+3
-3
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/logged_in_once.py
.../portal_skins/erp5_oauth2_authorisation/logged_in_once.py
+3
-3
bt5/erp5_oauth2_resource/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationClientConnector.py
...nents/document.erp5.OAuth2AuthorisationClientConnector.py
+13
-14
bt5/erp5_oauth2_resource/SkinTemplateItem/portal_skins/erp5_oauth2_resource/ERP5Site_preventLoginAttemptRetry.py
...erp5_oauth2_resource/ERP5Site_preventLoginAttemptRetry.py
+5
-6
bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.py
...plateItem/portal_skins/erp5_web_renderjs_ui/login_form.py
+2
-2
bt5/erp5_web_service/MixinTemplateItem/portal_components/mixin.erp5.RESTAPIClientConnectorMixin.py
...rtal_components/mixin.erp5.RESTAPIClientConnectorMixin.py
+6
-5
No files found.
bt5/erp5_oauth2_authorisation/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationServerConnector.py
View file @
c64c0018
...
...
@@ -31,8 +31,7 @@ from io import BytesIO
import
json
from
os
import
urandom
from
time
import
time
import
urllib
import
urlparse
from
six.moves.urllib.parse
import
parse_qsl
,
urlencode
,
urlsplit
,
urlunsplit
import
uuid
from
cryptography.hazmat.backends
import
default_backend
from
cryptography
import
fernet
...
...
@@ -145,7 +144,7 @@ def substituteRequest(
environ
=
request
.
environ
inner_environ_dict
=
environ
.
copy
()
inner_environ_dict
[
'REQUEST_METHOD'
]
=
method
inner_environ_dict
[
'QUERY_STRING'
]
=
url
lib
.
url
encode
(
query_list
)
inner_environ_dict
[
'QUERY_STRING'
]
=
urlencode
(
query_list
)
if
request
.
_auth
:
inner_environ_dict
[
'HTTP_AUTHORIZATION'
]
=
request
.
_auth
...
...
@@ -256,18 +255,18 @@ class _ERP5AuthorisationEndpoint(AuthorizationEndpoint):
if
is_local_client
and
self
.
__login_retry_url
:
# ...with a local resource server, redirect user agent to
# the provided login URL.
split_login_retry_url
=
url
parse
.
url
split
(
self
.
__login_retry_url
)
split_login_retry_url
=
urlsplit
(
self
.
__login_retry_url
)
return
(
(
(
'Location'
,
url
parse
.
url
unsplit
((
urlunsplit
((
split_login_retry_url
.
scheme
,
split_login_retry_url
.
netloc
,
split_login_retry_url
.
path
,
url
lib
.
url
encode
([
urlencode
([
(
x
,
y
)
for
x
,
y
in
urlparse
.
parse_qsl
(
split_login_retry_url
.
query
)
for
x
,
y
in
parse_qsl
(
split_login_retry_url
.
query
)
if
x
!=
'portal_status_message'
]
+
[(
'portal_status_message'
,
...
...
@@ -299,7 +298,7 @@ class _ERP5AuthorisationEndpoint(AuthorizationEndpoint):
credentials
=
credentials
,
)
if
authorization_status
==
302
and
is_local_client
:
split_location
=
url
parse
.
url
split
(
authorization_header_dict
[
'Location'
])
split_location
=
urlsplit
(
authorization_header_dict
[
'Location'
])
# XXX: to cut down on code complexity, this code has strong expectations on what location is.
_
,
client_connector_id
,
method_id
=
split_location
.
path
.
rsplit
(
'/'
,
2
)
if
method_id
!=
'loggedIn'
:
...
...
@@ -307,7 +306,7 @@ class _ERP5AuthorisationEndpoint(AuthorizationEndpoint):
client_connector_value
=
client_value
.
getParentValue
().
getParentValue
()[
client_connector_id
]
if
client_connector_value
.
getPortalType
()
!=
'OAuth2 Authorisation Client Connector'
:
raise
ValueError
(
split_location
.
path
)
query_list
=
urlparse
.
parse_qsl
(
split_location
.
query
)
query_list
=
parse_qsl
(
split_location
.
query
)
# Note: query string generation should not have produce any duplicate
# entries, so convert into a dict for code simplicity.
query_dict
=
{
...
...
@@ -385,7 +384,7 @@ class _ERP5AuthorisationEndpoint(AuthorizationEndpoint):
# Use the internal path back to us so it can be traversed to while
# still in the just-authenticated request.
(
self
.
__server_connector_path
+
'?'
+
url
parse
.
url
split
(
uri
).
query
self
.
__server_connector_path
+
'?'
+
urlsplit
(
uri
).
query
)
if
is_local_client
else
# Use the external URL back to us so user can be redirected to it,
# as they are then authenticated over multiple requests.
...
...
@@ -407,8 +406,8 @@ class _ERP5AuthorisationEndpoint(AuthorizationEndpoint):
login_form
=
neutral_context_value
.
login_form
portal_status_message_list
=
[
value
for
name
,
value
in
urlparse
.
parse_qsl
(
url
parse
.
url
split
(
came_from
).
query
,
for
name
,
value
in
parse_qsl
(
urlsplit
(
came_from
).
query
,
)
if
name
==
'portal_status_message'
]
...
...
@@ -763,8 +762,8 @@ class _ERP5RequestValidator(RequestValidator):
# redirect_uri path, but it may be under an extra layer of VirtualHost Monster
# magic.
# Client is declared local, accept any redirect URI on our scheme and netloc.
split_my_url
=
url
parse
.
url
split
(
client_value
.
absolute_url
())
split_redirect_uri
=
url
parse
.
url
split
(
redirect_uri
)
split_my_url
=
urlsplit
(
client_value
.
absolute_url
())
split_redirect_uri
=
urlsplit
(
redirect_uri
)
return
(
split_my_url
.
scheme
==
split_redirect_uri
.
scheme
and
split_my_url
.
netloc
==
split_redirect_uri
.
netloc
...
...
@@ -854,7 +853,7 @@ def _callEndpoint(endpoint, self, REQUEST):
if
request_body
is
None
and
content_type
==
'application/x-www-form-urlencoded'
:
# XXX: very imperfect, but should be good enough for OAuth2 usage:
# no standard OAuth2 POST field should be marshalled by Zope.
request_body
=
url
lib
.
url
encode
([
request_body
=
urlencode
([
(
x
,
y
)
for
x
,
y
in
six
.
iteritems
(
REQUEST
.
form
)
if
isinstance
(
y
,
six
.
string_types
)
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_getClientIdFromLoginOnceCameFrom.py
View file @
c64c0018
...
...
@@ -6,14 +6,14 @@ Once the user is authenticated, the same value can be accessed with:
from AccessControl import getSecurityManager
getSecurityManager().getUser().getClientId()
"""
import
urlparse
from
six.moves.urllib.parse
import
parse_qsl
,
urlsplit
# The came_from for login_once_form is special: it has no scheme, no netloc, a path and a query.
# Verify this so caller knows if they are providing the wrong value.
if
not
context
.
ERP5Site_isOAuth2CameFrom
(
came_from
=
came_from
):
raise
ValueError
result
,
=
[
value
for
name
,
value
in
urlparse
.
parse_qsl
(
urlparse
.
urlsplit
(
came_from
).
query
)
for
name
,
value
in
parse_qsl
(
urlsplit
(
came_from
).
query
)
if
name
==
'client_id'
]
return
result
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_isOAuth2CameFrom.py
View file @
c64c0018
...
...
@@ -2,8 +2,8 @@
OAuth2's /authorize endpoint produces a very specific format of came_from, with very specific meaning (not a real URL).
This script returns True value if given such came_from, and False otherwise.
"""
import
urlparse
parsed_came_from
=
url
parse
.
url
split
(
came_from
)
from
six.moves.urllib.parse
import
urlsplit
parsed_came_from
=
urlsplit
(
came_from
)
return
bool
(
not
parsed_came_from
.
scheme
and
not
parsed_came_from
.
netloc
and
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/ERP5Site_retryOAuth2Authorisation.py
View file @
c64c0018
...
...
@@ -3,16 +3,16 @@
Retry calling /authorize using the values in came_from
(which a previous call to /authorize generated, and is not a traditional came_from).
"""
import
urlparse
from
six.moves.urllib.parse
import
parse_qsl
,
urlsplit
from
erp5.component.document.OAuth2AuthorisationServerConnector
import
substituteRequest
if
not
context
.
ERP5Site_isOAuth2CameFrom
(
came_from
):
# came_from is broken, there is no way to call /authorize , so escape to wherever.
context
.
Base_redirect
()
return
parsed_came_from
=
url
parse
.
url
split
(
came_from
)
parsed_came_from
=
urlsplit
(
came_from
)
query_list
=
[
(
key
,
value
)
for
key
,
value
in
urlparse
.
parse_qsl
(
parsed_came_from
.
query
)
for
key
,
value
in
parse_qsl
(
parsed_came_from
.
query
)
if
key
!=
'portal_status_message'
]
if
portal_status_message
is
not
None
:
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_authorisation/SkinTemplateItem/portal_skins/erp5_oauth2_authorisation/logged_in_once.py
View file @
c64c0018
...
...
@@ -3,7 +3,7 @@
Similar to logged_in, but user authentication will only last for current request if nothing else is done.
So came_from must be honoured within the current request, and not redirected to.
"""
import
urlparse
from
six.moves.urllib.parse
import
parse_qsl
,
urlsplit
from
erp5.component.document.OAuth2AuthorisationServerConnector
import
substituteRequest
portal
=
context
.
getPortalObject
()
if
portal
.
portal_skins
.
updateSkinCookie
():
...
...
@@ -28,7 +28,7 @@ if not came_from or not context.ERP5Site_isOAuth2CameFrom(came_from):
# came_from is broken, there is no way to call authorize, so escape to wherever.
context
.
Base_redirect
()
return
parsed_came_from
=
url
parse
.
url
split
(
came_from
)
parsed_came_from
=
urlsplit
(
came_from
)
# Turn the ZODB path from came_from into a relative URL and base it on context (and not portal) to
# work as expected from within Web Sites without Virtual Host Monster relocating them above portal.
connector_value
=
context
.
restrictedTraverse
(
parsed_came_from
.
path
.
lstrip
(
'/'
))
...
...
@@ -40,7 +40,7 @@ if (
return
# Note: query string generation should not have produce any duplicate
# entries, so directly use to update form dict for code simplicity.
form
=
dict
(
urlparse
.
parse_qsl
(
parsed_came_from
.
query
))
form
=
dict
(
parse_qsl
(
parsed_came_from
.
query
))
login_retry_url
=
REQUEST
.
form
.
get
(
'login_retry_url'
)
if
login_retry_url
is
not
None
:
form
[
'login_retry_url'
]
=
login_retry_url
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_resource/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationClientConnector.py
View file @
c64c0018
...
...
@@ -31,13 +31,12 @@ import email.utils
import
functools
import
hashlib
import
hmac
import
httplib
from
six.moves.http_client
import
HTTPConnection
,
HTTPSConnection
import
json
from
os
import
urandom
import
random
from
time
import
time
import
urllib
import
urlparse
from
six.moves.urllib.parse
import
urlencode
,
urljoin
,
urlparse
import
ssl
from
AccessControl
import
(
ClassSecurityInfo
,
...
...
@@ -191,7 +190,7 @@ class _OAuth2AuthorisationServerProxy(object):
ca_certificate_pem
,
insecure
,
):
scheme
=
url
parse
.
url
split
(
authorisation_server_url
).
scheme
scheme
=
urlsplit
(
authorisation_server_url
).
scheme
if
scheme
!=
'https'
and
not
insecure
:
raise
ValueError
(
'Only https access to Authorisation Server is allowed'
)
self
.
_scheme
=
scheme
...
...
@@ -210,7 +209,7 @@ class _OAuth2AuthorisationServerProxy(object):
def
_query
(
self
,
method_id
,
body
,
header_dict
=
()):
plain_url
=
self
.
_authorisation_server_url
+
'/'
+
method_id
parsed_url
=
urlparse
.
urlparse
(
plain_url
)
parsed_url
=
urlparse
(
plain_url
)
if
self
.
_scheme
==
'https'
:
ssl_context
=
ssl
.
create_default_context
(
cadata
=
self
.
_ca_certificate_pem
,
...
...
@@ -222,11 +221,11 @@ class _OAuth2AuthorisationServerProxy(object):
ssl_context
.
verify_mode
=
ssl
.
CERT_REQUIRED
ssl_context
.
check_hostname
=
True
Connection
=
functools
.
partial
(
httplib
.
HTTPSConnection
,
HTTPSConnection
,
context
=
ssl_context
,
)
else
:
Connection
=
httplib
.
HTTPConnection
Connection
=
HTTPConnection
timeout
=
getTimeLeft
()
if
timeout
is
None
or
timeout
>
self
.
_timeout
:
timeout
=
self
.
_timeout
...
...
@@ -256,7 +255,7 @@ class _OAuth2AuthorisationServerProxy(object):
def
_queryERP5
(
self
,
method_id
,
kw
=
()):
header_dict
,
body
,
status
=
self
.
_query
(
method_id
=
method_id
,
body
=
url
lib
.
url
encode
(
kw
),
body
=
urlencode
(
kw
),
header_dict
=
{
'Accept'
:
'application/json;charset=UTF-8'
,
'Content-Type'
:
'application/x-www-form-urlencoded'
,
...
...
@@ -274,7 +273,7 @@ class _OAuth2AuthorisationServerProxy(object):
def
_queryOAuth2
(
self
,
method
,
REQUEST
,
RESPONSE
):
header_dict
,
body
,
status
=
self
.
_query
(
method
,
body
=
url
lib
.
url
encode
(
REQUEST
.
form
.
items
()),
body
=
urlencode
(
REQUEST
.
form
.
items
()),
header_dict
=
{
'CONTENT_TYPE'
:
REQUEST
.
environ
[
'CONTENT_TYPE'
],
},
...
...
@@ -377,7 +376,7 @@ class OAuth2AuthorisationClientConnector(
if
'/'
in
authorisation_server_url
:
# Remote Authorisation Server
return
_OAuth2AuthorisationServerProxy
(
authorisation_server_url
=
url
parse
.
url
join
(
authorisation_server_url
=
urljoin
(
# In case authorisation_server_url contains slashes but is still
# relative (to the scheme or to the netloc - path-relative is not
# supported by urljoin)
...
...
@@ -474,7 +473,7 @@ class OAuth2AuthorisationClientConnector(
assert
inner_response
.
status
==
200
access_token
=
oauth2_response
[
'access_token'
]
refresh_token
=
oauth2_response
.
get
(
'refresh_token'
)
parsed_actual_url
=
urlparse
.
urlparse
(
request
.
other
.
get
(
'ACTUAL_URL'
))
parsed_actual_url
=
urlparse
(
request
.
other
.
get
(
'ACTUAL_URL'
))
same_site
=
self
.
ERP5Site_getAuthCookieSameSite
(
scheme
=
parsed_actual_url
.
scheme
,
hostname
=
parsed_actual_url
.
hostname
,
...
...
@@ -712,8 +711,8 @@ class OAuth2AuthorisationClientConnector(
# came_from is what the user was trying to do just before they ended up
# here, so we can redirect them there once they are authenticated.
if
came_from
:
parsed_came_from
=
urlparse
.
urlparse
(
came_from
)
parsed_redirect_uri
=
urlparse
.
urlparse
(
redirect_uri
)
parsed_came_from
=
urlparse
(
came_from
)
parsed_redirect_uri
=
urlparse
(
redirect_uri
)
if
(
parsed_came_from
.
scheme
!=
parsed_redirect_uri
.
scheme
or
parsed_came_from
.
netloc
!=
parsed_redirect_uri
.
netloc
...
...
@@ -829,7 +828,7 @@ class OAuth2AuthorisationClientConnector(
'Location'
,
self
.
_getAuthorisationServerValue
(
REQUEST
=
REQUEST
,
).
absolute_url
()
+
'/authorize?'
+
url
lib
.
url
encode
(
query_list
),
).
absolute_url
()
+
'/authorize?'
+
urlencode
(
query_list
),
)
else
:
# Provide the current URL to authorize, so that it can redirect the
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_oauth2_resource/SkinTemplateItem/portal_skins/erp5_oauth2_resource/ERP5Site_preventLoginAttemptRetry.py
View file @
c64c0018
...
...
@@ -3,17 +3,16 @@ Modify given URL so that the resulting one prevents further login attempts when
Useful to break redirection loops.
"""
import
urllib
import
urlparse
from
six.moves.urllib.parse
import
parse_qsl
,
urlencode
,
urlsplit
,
urlunsplit
PARAMETER_NAME
=
'disable_cookie_login__'
parsed_url
=
url
parse
.
url
split
(
url
)
return
url
parse
.
url
unsplit
((
parsed_url
=
urlsplit
(
url
)
return
urlunsplit
((
parsed_url
.
scheme
,
parsed_url
.
netloc
,
parsed_url
.
path
,
url
lib
.
url
encode
([
urlencode
([
(
x
,
y
)
for
x
,
y
in
urlparse
.
parse_qsl
(
parsed_url
.
query
)
for
x
,
y
in
parse_qsl
(
parsed_url
.
query
)
if
x
!=
PARAMETER_NAME
]
+
[
(
PARAMETER_NAME
,
'1'
),
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.py
View file @
c64c0018
# Short-circuit old (pre-oauth2) web-mode "login_form"s
import
urllib
from
six.moves.urllib.parse
import
urlencode
web_section_value
=
context
.
getWebSectionValue
()
client_id
=
context
.
getPortalObject
().
ERP5Site_getOAuth2ClientConnectorClientId
(
connector_id
=
(
...
...
@@ -13,7 +13,7 @@ if client_id is None:
return
context
.
login_once_form
(
has_oauth2
=
False
)
if
came_from
:
# Make the user go through WebSite_login after authentication, so it does its url de-templatification magic
came_from
=
context
.
absolute_url
()
+
'/WebSite_login?'
+
url
lib
.
url
encode
(((
'came_from'
,
came_from
),
))
came_from
=
context
.
absolute_url
()
+
'/WebSite_login?'
+
urlencode
(((
'came_from'
,
came_from
),
))
return
context
.
skinSuper
(
'erp5_web_renderjs_ui'
,
script
.
id
)(
REQUEST
=
REQUEST
,
RESPONSE
=
RESPONSE
,
...
...
This diff is collapsed.
Click to expand it.
bt5/erp5_web_service/MixinTemplateItem/portal_components/mixin.erp5.RESTAPIClientConnectorMixin.py
View file @
c64c0018
...
...
@@ -26,10 +26,11 @@
#
##############################################################################
import
time
import
urlparse
import
ssl
import
httplib
import
json
from
six.moves.http_client
import
HTTPSConnection
from
six.moves.urllib.parse
import
urlparse
from
six
import
string_types
as
basestring
from
Products.ERP5Type.Timeout
import
getTimeLeft
from
contextlib
import
contextmanager
from
Products.ERP5Type.XMLObject
import
XMLObject
...
...
@@ -106,7 +107,7 @@ class RESTAPIClientConnectorMixin(XMLObject):
header_dict
[
'content-type'
]
=
'application/json'
body
=
json
.
dumps
(
body
)
plain_url
=
self
.
getBaseUrl
().
rstrip
(
'/'
)
+
'/'
+
path
.
lstrip
(
'/'
)
parsed_url
=
urlparse
.
urlparse
(
plain_url
)
parsed_url
=
urlparse
(
plain_url
)
ssl_context
=
ssl
.
create_default_context
(
cadata
=
self
.
getCaCertificatePem
(),
)
...
...
@@ -116,7 +117,7 @@ class RESTAPIClientConnectorMixin(XMLObject):
if
bind_address
:
bind_address
=
(
bind_address
,
0
)
time_left_before_timeout
=
getTimeLeft
()
http_connection
=
httplib
.
HTTPSConnection
(
http_connection
=
HTTPSConnection
(
host
=
parsed_url
.
hostname
,
port
=
parsed_url
.
port
,
strict
=
True
,
...
...
@@ -185,7 +186,7 @@ class RESTAPIClientConnectorMixin(XMLObject):
with
time_tracker
(
'call'
),
Deadline
(
timeout
):
# Limit numbers of retries, in case the authentication API succeeds
# but the token is not usable.
for
_
in
x
range
(
2
):
for
_
in
range
(
2
):
with
time_tracker
(
'token'
):
access_token
=
self
.
_getAccessToken
()
if
access_token
is
not
None
:
...
...
This diff is collapsed.
Click to expand it.
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