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
143
Merge Requests
143
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
a6281e66
Commit
a6281e66
authored
Oct 20, 2022
by
Kazuhiko Shiozaki
Committed by
Jérome Perrin
Mar 20, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
py2/py3: convert str <=> bytes.
parent
0e4394cc
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
35 additions
and
32 deletions
+35
-32
bt5/erp5_oauth2_authorisation/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationServerConnector.py
...nents/document.erp5.OAuth2AuthorisationServerConnector.py
+8
-7
bt5/erp5_oauth2_authorisation/TestTemplateItem/portal_components/test.erp5.testOAuth2Server.py
...plateItem/portal_components/test.erp5.testOAuth2Server.py
+10
-9
bt5/erp5_oauth2_resource/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationClientConnector.py
...nents/document.erp5.OAuth2AuthorisationClientConnector.py
+17
-16
No files found.
bt5/erp5_oauth2_authorisation/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationServerConnector.py
View file @
a6281e66
...
@@ -71,6 +71,7 @@ from DateTime import DateTime
...
@@ -71,6 +71,7 @@ from DateTime import DateTime
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type.Message
import
translateString
from
Products.ERP5Type.Message
import
translateString
from
Products.ERP5Type.UnrestrictedMethod
import
super_user
from
Products.ERP5Type.UnrestrictedMethod
import
super_user
from
Products.ERP5Type.Utils
import
bytes2str
,
str2bytes
,
unicode2str
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Security.ERP5GroupManager
import
(
from
Products.ERP5Security.ERP5GroupManager
import
(
disableCache
as
ERP5GroupManager_disableCache
,
disableCache
as
ERP5GroupManager_disableCache
,
...
@@ -536,7 +537,7 @@ class _ERP5RequestValidator(RequestValidator):
...
@@ -536,7 +537,7 @@ class _ERP5RequestValidator(RequestValidator):
def
_getClientValue
(
self
,
client_id
):
def
_getClientValue
(
self
,
client_id
):
try
:
try
:
result
=
self
.
_authorisation_server_connector_value
[
client_id
.
encode
(
'utf-8'
)]
result
=
self
.
_authorisation_server_connector_value
[
unicode2str
(
client_id
)]
except
KeyError
:
except
KeyError
:
return
return
if
result
.
getValidationState
()
==
'validated'
:
if
result
.
getValidationState
()
==
'validated'
:
...
@@ -1031,9 +1032,9 @@ class OAuth2AuthorisationServerConnector(XMLObject):
...
@@ -1031,9 +1032,9 @@ class OAuth2AuthorisationServerConnector(XMLObject):
(ex: "Authorization: Basic ..." request header).
(ex: "Authorization: Basic ..." request header).
"""
"""
try
:
try
:
login_retry_url
=
self
.
__getLoginRetryURLMultiFernet
().
decrypt
(
login_retry_url
=
bytes2str
(
self
.
__getLoginRetryURLMultiFernet
().
decrypt
(
base64
.
urlsafe_b64decode
(
REQUEST
.
form
[
'login_retry_url'
]),
base64
.
urlsafe_b64decode
(
REQUEST
.
form
[
'login_retry_url'
]),
)
)
)
except
(
fernet
.
InvalidToken
,
TypeError
,
KeyError
):
except
(
fernet
.
InvalidToken
,
TypeError
,
KeyError
):
# No login_retry_url provided or its value is unusable: if this is a GET
# No login_retry_url provided or its value is unusable: if this is a GET
# request (trying to display a login form), use the current URL.
# request (trying to display a login form), use the current URL.
...
@@ -1047,9 +1048,9 @@ class OAuth2AuthorisationServerConnector(XMLObject):
...
@@ -1047,9 +1048,9 @@ class OAuth2AuthorisationServerConnector(XMLObject):
def
getSignedLoginRetryUrl
():
def
getSignedLoginRetryUrl
():
if
login_retry_url
is
None
:
if
login_retry_url
is
None
:
return
None
return
None
return
base64
.
urlsafe_b64encode
(
return
b
ytes2str
(
b
ase64
.
urlsafe_b64encode
(
self
.
__getLoginRetryURLMultiFernet
().
encrypt
(
login_retry_url
),
self
.
__getLoginRetryURLMultiFernet
().
encrypt
(
str2bytes
(
login_retry_url
)
),
)
)
)
return
_ERP5AuthorisationEndpoint
(
return
_ERP5AuthorisationEndpoint
(
server_connector_path
=
self
.
getPath
(),
server_connector_path
=
self
.
getPath
(),
zope_request
=
REQUEST
,
zope_request
=
REQUEST
,
...
@@ -1083,7 +1084,7 @@ class OAuth2AuthorisationServerConnector(XMLObject):
...
@@ -1083,7 +1084,7 @@ class OAuth2AuthorisationServerConnector(XMLObject):
query_list
=
query_list
+
[(
query_list
=
query_list
+
[(
'login_retry_url'
,
'login_retry_url'
,
base64
.
urlsafe_b64encode
(
base64
.
urlsafe_b64encode
(
self
.
__getLoginRetryURLMultiFernet
().
encrypt
(
login_retry_url
),
self
.
__getLoginRetryURLMultiFernet
().
encrypt
(
str2bytes
(
login_retry_url
)
),
),
),
)],
)],
)
as
inner_request
:
)
as
inner_request
:
...
...
bt5/erp5_oauth2_authorisation/TestTemplateItem/portal_components/test.erp5.testOAuth2Server.py
View file @
a6281e66
...
@@ -41,6 +41,7 @@ import six
...
@@ -41,6 +41,7 @@ import six
from
AccessControl.SecurityManagement
import
getSecurityManager
,
setSecurityManager
from
AccessControl.SecurityManagement
import
getSecurityManager
,
setSecurityManager
from
DateTime
import
DateTime
from
DateTime
import
DateTime
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Products.ERP5Type.Utils
import
bytes2str
,
str2bytes
from
Products.ERP5.ERP5Site
import
(
from
Products.ERP5.ERP5Site
import
(
ERP5_AUTHORISATION_EXTRACTOR_USERNAME_NAME
,
ERP5_AUTHORISATION_EXTRACTOR_USERNAME_NAME
,
ERP5_AUTHORISATION_EXTRACTOR_PASSWORD_NAME
,
ERP5_AUTHORISATION_EXTRACTOR_PASSWORD_NAME
,
...
@@ -549,7 +550,7 @@ class TestOAuth2(ERP5TypeTestCase):
...
@@ -549,7 +550,7 @@ class TestOAuth2(ERP5TypeTestCase):
self
.
assertContentTypeEqual
(
result_header_dict
,
'text/html'
)
self
.
assertContentTypeEqual
(
result_header_dict
,
'text/html'
)
assert
result_body
assert
result_body
parser
=
FormExtractor
()
parser
=
FormExtractor
()
parser
.
feed
(
result_body
)
parser
.
feed
(
bytes2str
(
result_body
)
)
parser
.
close
()
parser
.
close
()
(
action_url
,
field_list
),
=
parser
.
form_list
# pylint: disable=unbalanced-tuple-unpacking
(
action_url
,
field_list
),
=
parser
.
form_list
# pylint: disable=unbalanced-tuple-unpacking
for
field_name
,
_
in
field_list
:
for
field_name
,
_
in
field_list
:
...
@@ -566,13 +567,13 @@ class TestOAuth2(ERP5TypeTestCase):
...
@@ -566,13 +567,13 @@ class TestOAuth2(ERP5TypeTestCase):
content_type
=
'application/x-www-form-urlencoded'
,
content_type
=
'application/x-www-form-urlencoded'
,
header_dict
=
header_dict
,
header_dict
=
header_dict
,
cookie_dict
=
cookie_dict
,
cookie_dict
=
cookie_dict
,
body
=
urlencode
(
list
(
value_callback
(
body
=
str2bytes
(
urlencode
(
list
(
value_callback
(
field_item_list
=
tuple
(
field_item_list
=
tuple
(
(
key
,
value
)
(
key
,
value
)
for
key
,
value
in
field_list
for
key
,
value
in
field_list
if
not
key
.
endswith
(
':method'
)
if
not
key
.
endswith
(
':method'
)
),
),
))),
)))
)
,
)
)
if
script_id
==
'Base_callDialogMethod'
and
status
==
302
:
if
script_id
==
'Base_callDialogMethod'
and
status
==
302
:
# Base_callDialogMethod ended in redirection. It may be that the action
# Base_callDialogMethod ended in redirection. It may be that the action
...
@@ -781,9 +782,9 @@ class TestOAuth2(ERP5TypeTestCase):
...
@@ -781,9 +782,9 @@ class TestOAuth2(ERP5TypeTestCase):
"""
"""
Get a token, renew it, terminate session.
Get a token, renew it, terminate session.
"""
"""
basic_auth
=
'Basic '
+
base64
.
encodestring
(
basic_auth
=
'Basic '
+
b
ytes2str
(
b
ase64
.
encodestring
(
_TEST_USER_LOGIN
+
':'
+
self
.
__password
,
str2bytes
(
_TEST_USER_LOGIN
+
':'
+
self
.
__password
)
,
).
rstrip
()
)
)
.
rstrip
()
oauth2_server_connector
=
self
.
__oauth2_server_connector_value
.
getPath
()
oauth2_server_connector
=
self
.
__oauth2_server_connector_value
.
getPath
()
oauth2_client_declaration_value
=
self
.
__oauth2_external_client_declaration
oauth2_client_declaration_value
=
self
.
__oauth2_external_client_declaration
authorisation_code_lifespan
=
oauth2_client_declaration_value
.
getAuthorisationCodeLifespan
()
authorisation_code_lifespan
=
oauth2_client_declaration_value
.
getAuthorisationCodeLifespan
()
...
@@ -802,7 +803,7 @@ class TestOAuth2(ERP5TypeTestCase):
...
@@ -802,7 +803,7 @@ class TestOAuth2(ERP5TypeTestCase):
# Client produces a PKCE secret and sends the Resource Owner to the Authorisation Server
# Client produces a PKCE secret and sends the Resource Owner to the Authorisation Server
# to authorise them, getting an ahutorisation code.
# to authorise them, getting an ahutorisation code.
code_verifier
=
base64
.
urlsafe_b64encode
(
code_verifier
=
base64
.
urlsafe_b64encode
(
'this is not a good secret6789012'
,
# 32 bytes
b
'this is not a good secret6789012'
,
# 32 bytes
)
)
reference_state
=
'dummy'
reference_state
=
'dummy'
client_id
=
oauth2_client_declaration_value
.
getId
()
client_id
=
oauth2_client_declaration_value
.
getId
()
...
@@ -813,9 +814,9 @@ class TestOAuth2(ERP5TypeTestCase):
...
@@ -813,9 +814,9 @@ class TestOAuth2(ERP5TypeTestCase):
'client_id'
:
client_id
,
'client_id'
:
client_id
,
'state'
:
reference_state
,
'state'
:
reference_state
,
'code_challenge_method'
:
'S256'
,
'code_challenge_method'
:
'S256'
,
'code_challenge'
:
base64
.
urlsafe_b64encode
(
'code_challenge'
:
b
ytes2str
(
b
ase64
.
urlsafe_b64encode
(
hashlib
.
sha256
(
code_verifier
).
digest
(),
hashlib
.
sha256
(
code_verifier
).
digest
(),
).
rstrip
(
'='
),
)
)
.
rstrip
(
'='
),
'redirect_uri'
:
_EXTERNAL_CLIENT_REDIRECT_URI
,
'redirect_uri'
:
_EXTERNAL_CLIENT_REDIRECT_URI
,
}),
}),
redirect_uri
=
_EXTERNAL_CLIENT_REDIRECT_URI
,
redirect_uri
=
_EXTERNAL_CLIENT_REDIRECT_URI
,
...
...
bt5/erp5_oauth2_resource/DocumentTemplateItem/portal_components/document.erp5.OAuth2AuthorisationClientConnector.py
View file @
a6281e66
...
@@ -36,7 +36,7 @@ import json
...
@@ -36,7 +36,7 @@ import json
from
os
import
urandom
from
os
import
urandom
import
random
import
random
from
time
import
time
from
time
import
time
from
six.moves.urllib.parse
import
urlencode
,
urljoin
,
urlparse
from
six.moves.urllib.parse
import
urlencode
,
urljoin
,
urlparse
,
urlsplit
import
ssl
import
ssl
from
AccessControl
import
(
from
AccessControl
import
(
ClassSecurityInfo
,
ClassSecurityInfo
,
...
@@ -51,6 +51,7 @@ from OFS.Traversable import NotFound
...
@@ -51,6 +51,7 @@ from OFS.Traversable import NotFound
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Type.Timeout
import
getTimeLeft
from
Products.ERP5Type.Timeout
import
getTimeLeft
from
Products.ERP5Type.Utils
import
bytes2str
,
str2bytes
,
str2unicode
from
Products.ERP5Security.ERP5OAuth2ResourceServerPlugin
import
(
from
Products.ERP5Security.ERP5OAuth2ResourceServerPlugin
import
(
OAuth2AuthorisationClientConnectorMixIn
,
OAuth2AuthorisationClientConnectorMixIn
,
ERP5OAuth2ResourceServerPlugin
,
ERP5OAuth2ResourceServerPlugin
,
...
@@ -156,9 +157,9 @@ class _SimpleHTTPRequest(object):
...
@@ -156,9 +157,9 @@ class _SimpleHTTPRequest(object):
def
_authUserPW
(
self
):
def
_authUserPW
(
self
):
if
self
.
_auth
.
lower
().
startswith
(
'basic '
):
if
self
.
_auth
.
lower
().
startswith
(
'basic '
):
return
base64
.
decodestring
(
return
b
ytes2str
(
b
ase64
.
decodestring
(
self
.
_auth
.
split
(
None
,
1
)[
1
],
self
.
_auth
.
split
(
None
,
1
)[
1
],
).
split
(
':'
,
1
)
)
)
.
split
(
':'
,
1
)
def
get
(
self
,
name
):
def
get
(
self
,
name
):
if
name
==
'BODY'
:
if
name
==
'BODY'
:
...
@@ -200,7 +201,7 @@ class _OAuth2AuthorisationServerProxy(object):
...
@@ -200,7 +201,7 @@ class _OAuth2AuthorisationServerProxy(object):
self
.
_bind_address
=
(
bind_address
,
0
)
if
bind_address
else
None
self
.
_bind_address
=
(
bind_address
,
0
)
if
bind_address
else
None
if
ca_certificate_pem
is
not
None
:
if
ca_certificate_pem
is
not
None
:
# On python2 cadata is expected as an unicode object only.
# On python2 cadata is expected as an unicode object only.
ca_certificate_pem
=
ca_certificate_pem
.
decode
(
'utf-8'
)
ca_certificate_pem
=
str2unicode
(
ca_certificate_pem
)
self
.
_ca_certificate_pem
=
ca_certificate_pem
self
.
_ca_certificate_pem
=
ca_certificate_pem
#
#
...
@@ -580,7 +581,7 @@ class OAuth2AuthorisationClientConnector(
...
@@ -580,7 +581,7 @@ class OAuth2AuthorisationClientConnector(
)
)
RESPONSE
.
setCookie
(
RESPONSE
.
setCookie
(
name
=
name
,
name
=
name
,
value
=
b
ase64
.
urlsafe_b64encode
(
content
),
value
=
b
ytes2str
(
base64
.
urlsafe_b64encode
(
str2bytes
(
content
))
),
# prevent this cookie from being read over the network
# prevent this cookie from being read over the network
# (assuming an uncompromised SSL setup, but if it is compromised
# (assuming an uncompromised SSL setup, but if it is compromised
# then the attacker may just as well impersonate the victim using
# then the attacker may just as well impersonate the victim using
...
@@ -615,10 +616,10 @@ class OAuth2AuthorisationClientConnector(
...
@@ -615,10 +616,10 @@ class OAuth2AuthorisationClientConnector(
ttl
=
self
.
_SESSION_STATE_VALIDITY
ttl
=
self
.
_SESSION_STATE_VALIDITY
for
name
,
value
in
six
.
iteritems
(
self
.
_getRawStateCookieDict
(
REQUEST
)):
for
name
,
value
in
six
.
iteritems
(
self
.
_getRawStateCookieDict
(
REQUEST
)):
try
:
try
:
result
[
name
]
=
decrypt
(
result
[
name
]
=
bytes2str
(
decrypt
(
base64
.
urlsafe_b64decode
(
value
),
base64
.
urlsafe_b64decode
(
value
),
ttl
=
ttl
,
ttl
=
ttl
,
)
)
)
except
(
fernet
.
InvalidToken
,
TypeError
):
except
(
fernet
.
InvalidToken
,
TypeError
):
self
.
_expireStateCookie
(
RESPONSE
,
name
)
self
.
_expireStateCookie
(
RESPONSE
,
name
)
return
result
return
result
...
@@ -752,8 +753,8 @@ class OAuth2AuthorisationClientConnector(
...
@@ -752,8 +753,8 @@ class OAuth2AuthorisationClientConnector(
)))
)))
except
StopIteration
:
except
StopIteration
:
name
=
None
name
=
None
identifier
=
b
ase64
.
urlsafe_b64encode
(
urandom
(
32
))
identifier
=
b
ytes2str
(
base64
.
urlsafe_b64encode
(
urandom
(
32
)
))
code_verifier
=
b
ase64
.
urlsafe_b64encode
(
urandom
(
32
))
code_verifier
=
b
ytes2str
(
base64
.
urlsafe_b64encode
(
urandom
(
32
)
))
_
,
state_key
=
self
.
__getStateFernetKeyList
()[
0
]
_
,
state_key
=
self
.
__getStateFernetKeyList
()[
0
]
encrypt
=
fernet
.
Fernet
(
state_key
).
encrypt
encrypt
=
fernet
.
Fernet
(
state_key
).
encrypt
query_list
=
[
query_list
=
[
...
@@ -765,7 +766,7 @@ class OAuth2AuthorisationClientConnector(
...
@@ -765,7 +766,7 @@ class OAuth2AuthorisationClientConnector(
# Note: fernet both signs and encrypts the content.
# Note: fernet both signs and encrypts the content.
# It uses on AES128-CBC, PKCS7 padding, and SHA256 HMAC, with
# It uses on AES128-CBC, PKCS7 padding, and SHA256 HMAC, with
# independent keys for encryption and authentication.
# independent keys for encryption and authentication.
encrypt
(
json
.
dumps
({
bytes2str
(
encrypt
(
str2bytes
(
json
.
dumps
({
# Identifier is also stored in User-Agent as a cookie.
# Identifier is also stored in User-Agent as a cookie.
# This is used to prevent an attacker from tricking a user into
# This is used to prevent an attacker from tricking a user into
# giving us an Authorisation Code under the control of the attacker.
# giving us an Authorisation Code under the control of the attacker.
...
@@ -787,7 +788,7 @@ class OAuth2AuthorisationClientConnector(
...
@@ -787,7 +788,7 @@ class OAuth2AuthorisationClientConnector(
# done above), this means the key may be attacked using (partially)
# done above), this means the key may be attacked using (partially)
# chosen-cleartext (if AES128 is found vulnerable to such attack).
# chosen-cleartext (if AES128 is found vulnerable to such attack).
_STATE_CAME_FROM_NAME
:
(
_STATE_CAME_FROM_NAME
:
(
came_from
.
decode
(
'utf-8'
)
str2unicode
(
came_from
)
if
came_from
else
if
came_from
else
came_from
came_from
),
),
...
@@ -795,15 +796,15 @@ class OAuth2AuthorisationClientConnector(
...
@@ -795,15 +796,15 @@ class OAuth2AuthorisationClientConnector(
# Authorisation Code converted into tokens. To be kept secret from
# Authorisation Code converted into tokens. To be kept secret from
# everyone other than this server.
# everyone other than this server.
_STATE_CODE_VERIFIER_NAME
:
code_verifier
,
_STATE_CODE_VERIFIER_NAME
:
code_verifier
,
})),
}))
))
,
),
),
(
'code_challenge_method'
,
'S256'
),
(
'code_challenge_method'
,
'S256'
),
(
(
'code_challenge'
,
'code_challenge'
,
# S256 standard PKCE encoding
# S256 standard PKCE encoding
base64
.
urlsafe_b64encode
(
b
ytes2str
(
b
ase64
.
urlsafe_b64encode
(
hashlib
.
sha256
(
code_verifier
).
digest
(),
hashlib
.
sha256
(
str2bytes
(
code_verifier
)
).
digest
(),
).
rstrip
(
'='
),
)
)
.
rstrip
(
'='
),
),
),
]
]
if
scope_list
:
if
scope_list
:
...
@@ -817,7 +818,7 @@ class OAuth2AuthorisationClientConnector(
...
@@ -817,7 +818,7 @@ class OAuth2AuthorisationClientConnector(
self
.
_setStateCookie
(
self
.
_setStateCookie
(
RESPONSE
=
RESPONSE
,
RESPONSE
=
RESPONSE
,
name
=
name
,
name
=
name
,
content
=
encrypt
(
identifier
),
content
=
bytes2str
(
encrypt
(
str2bytes
(
identifier
))
),
)
)
if
(
if
(
self
.
isAuthorisationServerRemote
()
or
self
.
isAuthorisationServerRemote
()
or
...
...
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