Commit 159b0817 authored by Vincent Pelletier's avatar Vincent Pelletier

erp5_web_renderjs_ui: Add minimal oauth2 token support.

This should evolve to become a browser-side OAuth2 client.
parent 035d099a
......@@ -218,6 +218,7 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_monaco_editor',
'erp5_multimedia',
'erp5_notebook',
'erp5_oauth2_resource',
'erp5_officejs',
'erp5_officejs_connector',
'erp5_officejs_jquery_app',
......
......@@ -62,12 +62,12 @@
<!-- Then access the homepage to make sure the login form still can appear -->
<tr>
<td>waitForElementPresent</td>
<td>//input[@name="WebSite_login:method"]</td>
<td>//input[@value="Login"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//input[@name="WebSite_login:method"]</td>
<td>//input[@value="Login"]</td>
<td></td>
</tr>
<tr>
......@@ -77,24 +77,19 @@
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//input[@name="WebSite_login:method"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>click</td>
<td>WebSite_login:method</td>
<td>//input[@value="Login"]</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: None;
wait python: False;
submit_name python: '//input[@value=\'Login\']';
">
<tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_logout_test</tal:block>
<tal:block metal:fill-slot="password">user_logout_test</tal:block>
</tal:block>
</tal:block>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_header.html')]//h1</td>
......
......@@ -91,6 +91,7 @@
<string>my_configuration_stylesheet_url</string>
<string>my_configuration_wallpaper_url</string>
<string>my_configuration_icon_url</string>
<string>my_configuration_oauth2_client_connector_id</string>
</list>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_configuration_oauth2_client_connector_id</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>OAuth2 Client Connector Id</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# XXX: minimal copy of xhtml_style's implementation, used by OAuth2 authentication.
# This should be removed once erp5js implements outh2 protocol directly instead of going through login forms
from ZTUtils import make_query
# BBB: originally, form_id was the first positional argument
if not redirect_url or '/' not in redirect_url:
form_id = redirect_url or form_id
redirect_url = context.absolute_url()
if form_id:
if not redirect_url.endswith('/'):
redirect_url += '/'
redirect_url += form_id
if keep_items:
redirect_url += '?' + make_query(keep_items)
context.getPortalObject().REQUEST.RESPONSE.redirect(
redirect_url,
status=status_code,
)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>redirect_url=None, keep_items=(), status_code=302, form_id=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_redirect</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# Short-circuit old (pre-oauth2) web-mode "login_form"s
import urllib
web_section_value = context.getWebSectionValue()
client_id = context.getPortalObject().ERP5Site_getOAuth2ClientConnectorClientId(
connector_id=(
None
if web_section_value is None else
web_section_value.getLayoutProperty('configuration_oauth2_client_connector_id', default=None)
),
)
if client_id is None:
# BBB: OAuth2 is not enabled
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?' + urllib.urlencode((('came_from', came_from), ))
return context.skinSuper('erp5_web_renderjs_ui', script.id)(
REQUEST=REQUEST,
RESPONSE=RESPONSE,
client_id=client_id,
came_from=came_from,
portal_status_message=portal_status_message,
)
......@@ -2,10 +2,14 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
......@@ -20,6 +24,18 @@
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
......@@ -33,25 +49,13 @@
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
<key> <string>_params</string> </key>
<value> <string>REQUEST, RESPONSE, came_from=None, portal_status_message=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>login_form</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>login_once_form</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html tal:define="form_action string:WebSite_login;
absolute_url context/absolute_url;
portal context/getPortalObject;
<html tal:define="
ERP5Site python: modules['Products.ERP5.ERP5Site'];
has_oauth2 python: options.get('has_oauth2', True);
form_action python: 'logged_in_once' if has_oauth2 else 'WebSite_login';
absolute_url python: context.absolute_url() + '/';
web_site_value python: context.getWebSiteValue();
portal python: context.getPortalObject();
root_absolute_url python: (portal if web_site_value is None else web_site_value).absolute_url() + '/';
available_oauth_login_list python: portal.ERP5Site_getAvailableOAuthLoginList();
enable_google_login python: 'google' in available_oauth_login_list;
enable_facebook_login python: 'facebook' in available_oauth_login_list;
......@@ -9,7 +14,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title tal:content="portal/getTitle"></title>
<title tal:content="python: portal.getTitle()"></title>
<link rel="stylesheet" href="gadget_erp5_nojqm.css">
</head>
......@@ -32,42 +37,47 @@
<div class="gadget-content">
<article>
<section>
<div class="visible" data-gadget-scope="notification" tal:condition="exists: request/portal_status_message">
<button type="submit" class="error" tal:attributes="data-i18n request/portal_status_message"><span tal:content="request/portal_status_message"></span></button>
<div class="visible" data-gadget-scope="notification" tal:condition="python: 'portal_status_message' in request">
<button type="submit" class="error" tal:attributes="data-i18n python: request['portal_status_message']"><span tal:content="python: request['portal_status_message']"></span></button>
</div>
</section>
<section tal:condition="not: portal/portal_membership/isAnonymousUser">
<p i18n:domain="ui" i18n:translate="" >It seems you're already authenticated.</p>
<p><a tal:condition="exists: request/came_from"
tal:attributes="href python:context.WebSection_renderCameFromURITemplate(request.came_from)" >Go back</a></p>
</section>
<section tal:condition="portal/portal_membership/isAnonymousUser">
<section>
<section class="ui-content-header-plain">
<h3 class="ui-content-title ui-body-c">
<span class="ui-icon ui-icon-custom ui-icon-sign-in"></span>
<tal:block i18n:domain="ui" i18n:translate="">Log in</tal:block>
</h3>
</section>
<form method="post" tal:attributes="action python: '%s/' % absolute_url" class="field_container">
<form method="post" tal:attributes="action python: absolute_url" class="field_container">
<tal:block tal:condition="python: has_oauth2">
<input type="hidden"
tal:attributes="
name python: ERP5Site.ERP5_AUTHORISATION_EXTRACTOR_MARKER_NAME;
value python: ERP5Site.ERP5_AUTHORISATION_EXTRACTOR_MARKER_VALUE;
"
/>
<input type="hidden"
name="login_retry_url"
tal:attributes="value python: request.get('login_retry_url', '')"
/>
</tal:block>
<div>
<div>
<div class="ui-field-contain">
<label i18n:domain="ui" i18n:translate="" >Username</label>
<div><input autofocus type="text" name="__ac_name" value="" required=""></div>
<div><input autofocus type="text" value="" required="" tal:attributes="name python: ERP5Site.ERP5_AUTHORISATION_EXTRACTOR_USERNAME_NAME if has_oauth2 else '__ac_name'"></div>
</div>
<div class="ui-field-contain">
<label i18n:domain="ui" i18n:translate="" >Password</label>
<div><input type="password" name="__ac_password" value="" autocomplete="off" /></div>
<div><input type="password" value="" autocomplete="off" tal:attributes="name python: ERP5Site.ERP5_AUTHORISATION_EXTRACTOR_PASSWORD_NAME if has_oauth2 else '__ac_password'"/></div>
</div>
<div class="dialog_button_container">
<input type="submit" value="Login" i18n:attributes="value" i18n:domain="ui" tal:attributes="name python: '%s:method' % (form_action, )"/>
<a i18n:domain="ui" i18n:translate="" tal:attributes="href python: '%s/WebSite_viewRecoverAccount?came_from=%s' % (absolute_url, absolute_url)">I forgot my password!</a>
<a i18n:domain="ui" i18n:translate="" tal:attributes="href python: '%sWebSite_viewRecoverAccount?%s' % (absolute_url, modules['urllib'].urlencode([('came_from', absolute_url)]))">I forgot my password!</a>
</div>
<div class="dialog_button_container" tal:condition="enable_google_login"
tal:define="current_url python: context.getWebSiteValue().absolute_url()">
<a tal:attributes="href string:${current_url}/ERP5Site_redirectToGoogleLoginPage"
<div class="dialog_button_container" tal:condition="enable_google_login">
<a tal:attributes="href python: root_absolute_url + 'ERP5Site_redirectToGoogleLoginPage'"
i18n:translate=""
i18n:domain="ui"
class="sign_in_with_google"
......@@ -76,9 +86,8 @@
</a>
</div>
<div class="dialog_button_container" tal:condition="enable_facebook_login"
tal:define="current_url python: context.getWebSiteValue().absolute_url()">
<a tal:attributes="href string:${current_url}/ERP5Site_redirectToFacebookLoginPage"
<div class="dialog_button_container" tal:condition="enable_facebook_login">
<a tal:attributes="href python: root_absolute_url + 'ERP5Site_redirectToFacebookLoginPage'"
i18n:translate=""
i18n:domain="ui"
class="sign_in_with_facebook"
......@@ -87,9 +96,8 @@
<img alt="Login with Facebook" src="facebook_login_button.png">
</a>
</div>
<div class="dialog_button_container" tal:condition="enable_openidconnect_login"
tal:define="current_url python: context.getWebSiteValue().absolute_url()">
<a tal:attributes="href string:${current_url}/ERP5Site_redirectToOpenIdLoginPage"
<div class="dialog_button_container" tal:condition="enable_openidconnect_login">
<a tal:attributes="href python: root_absolute_url + 'ERP5Site_redirectToOpenIdLoginPage'"
i18n:translate=""
i18n:domain="ui"
class="sign_in_with_openid"
......@@ -103,9 +111,9 @@
</div>
<input type="hidden" name="url" tal:attributes="value absolute_url" />
<input tal:condition="exists: request/came_from"
<input tal:condition="python: 'came_from' in request"
type="hidden" name="came_from"
tal:attributes="value request/came_from" />
tal:attributes="value python: request['came_from']" />
</form>
</section>
</article>
......
erp5_hal_json_style
erp5_dms
erp5_font
erp5_oauth2_resource
\ No newline at end of file
......@@ -99,34 +99,15 @@
<td></td>
</tr>
<tr>
<td>openAndWait</td>
<td>${base_url}</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//input[@name='__ac_name']</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: '${base_url}';
submit_name python: '//input[@value=\'Login\']';
">
<tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_logout_test</tal:block>
<tal:block metal:fill-slot="password">user_logout_test</tal:block>
</tal:block>
</tal:block>
<tr>
<td>waitForTextPresent</td>
......@@ -198,34 +179,15 @@
<td></td>
</tr>
<tr>
<td>openAndWait</td>
<td>${base_url}</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//input[@name='__ac_name']</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: '${base_url}';
submit_name python: '//input[@value=\'Login\']';
">
<tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_logout_test</tal:block>
<tal:block metal:fill-slot="password">user_logout_test</tal:block>
</tal:block>
</tal:block>
<tr>
<td>waitForTextPresent</td>
......
......@@ -83,21 +83,16 @@
<td></td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>click</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: None;
wait python: False;
submit_name python: '//input[@value=\'Login\']';
">
<tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_logout_test</tal:block>
<tal:block metal:fill-slot="password">user_logout_test</tal:block>
</tal:block>
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
......@@ -181,21 +176,14 @@
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>user_logout_test</td>
</tr>
<tr>
<td>click</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: None;
wait python: False;
submit_name python: '//input[@value=\'Login\']';
"><tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_logout_test</tal:block>
<tal:block metal:fill-slot="password">user_logout_test</tal:block>
</tal:block></tal:block>
<tr>
<td>waitForElementPresent</td>
......
......@@ -185,13 +185,13 @@
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//input[@name='__ac_name']</td>
<td>waitForTextPresent</td>
<td>Username</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//input[@name='__ac_password']</td>
<td>assertTextPresent</td>
<td>Password</td>
<td></td>
</tr>
<tr>
......@@ -199,25 +199,20 @@
<td>Password changed.</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_name']</td>
<td>user_a_test</td>
</tr>
<tr>
<td>type</td>
<td>//input[@name='__ac_password']</td>
<td>123</td>
</tr>
<tr>
<td>click</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tal:block tal:define="
login_form_url python: None;
wait python: False;
submit_name python: '//input[@value=\'Login\']';
">
<tal:block metal:use-macro="python: context.Zuite_CommonTemplate.macros['login']">
<tal:block metal:fill-slot="username">user_a_test</tal:block>
<tal:block metal:fill-slot="password">123</tal:block>
</tal:block>
</tal:block>
<!--User can access even has no access to it's person document -->
<tr>
<td>waitForElementNotPresent</td>
<td>//input[@name='__ac_name']</td>
<td>//input[@value='Login']</td>
<td></td>
</tr>
<tr>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment