diff --git a/examples/demo/demo-safe.ecf b/examples/demo/demo-safe.ecf index b8c67db..b00a415 100644 --- a/examples/demo/demo-safe.ecf +++ b/examples/demo/demo-safe.ecf @@ -31,6 +31,7 @@ + diff --git a/examples/demo/site/modules/session_auth/files/js/roc_basic_auth.js b/examples/demo/site/modules/session_auth/files/js/roc_basic_auth.js new file mode 100644 index 0000000..467bcd4 --- /dev/null +++ b/examples/demo/site/modules/session_auth/files/js/roc_basic_auth.js @@ -0,0 +1,325 @@ +var ROC_AUTH = ROC_AUTH || { }; + +var loginURL = "/basic_auth_login"; +var logoutURL = "/basic_auth_logoff"; + +var userAgent = navigator.userAgent.toLowerCase(); +var firstLogIn = true; + +ROC_AUTH.login = function() { + var form = document.forms['cms_basic_auth']; + var username = form.username.value; + var password = form.password.value; + //var host = form.host.value; + var origin = window.location.origin + window.location.pathname; + var _login = function(){ + + + if (document.getElementById('myModalFormId') !== null ) { + ROC_AUTH.remove ('myModalFormId'); + } + + + if (username === "" || password === "") { + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + } + }else{ + + //Instantiate HTTP Request + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", loginURL, true, username, password); + request.send(null); + + //Process Response + request.onreadystatechange = function(){ + if (request.readyState == 4) { + if (request.status==200) { + delete form; + window.location=window.location.origin; + } + else{ + if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){ + } + + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + } + + } + } + } + } + } + + var userAgent = navigator.userAgent.toLowerCase(); + if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + if (firstLogIn) _login(); + else logoff(_login); + } + else{ + _login(); + } + + if (firstLogIn) firstLogIn = false; +}; + + +ROC_AUTH.login_with_redirect = function() { + var form = document.forms[2]; + var username = form.username.value; + var password = form.password.value; + var host = form.host.value; + var _login = function(){ + + var redirectURL = form.redirect && form.redirect.value || ""; + + + $("#imgProgressRedirect").show(); + + if (document.getElementById('myModalFormId') !== null ) { + ROC_AUTH.remove ('myModalFormId'); + } + + + if (username === "" || password === "") { + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + $("#imgProgressRedirect").hide(); + } + }else{ + + //Instantiate HTTP Request + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", host.concat(loginURL), true, username, password); + request.send(null); + + //Process Response + request.onreadystatechange = function(){ + if (request.readyState == 4) { + if (request.status==200) { + if (redirectURL === "") { + window.location=host.concat("/"); + } else { + window.location=host.concat(redirectURL); + } + + } + else{ + if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){ + } + + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + $("#imgProgressRedirect").hide(); + } + + } + } + } + } + } + + var userAgent = navigator.userAgent.toLowerCase(); + if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + if (firstLogIn) _login(); + else logoff(_login); + } + else{ + _login(); + } + + if (firstLogIn) firstLogIn = false; +}; + + +ROC_AUTH.getQueryParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " ")); +} + +ROC_AUTH.logoff = function(callback){ + var form = document.forms[0]; + var host = form.host.value; + + if (userAgent.indexOf("msie") != -1) { + document.execCommand("ClearAuthenticationCache"); + } + else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + + var request1 = new XMLHttpRequest(); + var request2 = new XMLHttpRequest(); + + //Logout. Tell the server not to return the "WWW-Authenticate" header + request1.open("GET", host.concat(logoutURL) + "?prompt=false", true); + request1.send(""); + request1.onreadystatechange = function(){ + if (request1.readyState == 4) { + + //Sign in with dummy credentials to clear the auth cache + request2.open("GET", host.concat(logoutURL), true, "logout", "logout"); + request2.send(""); + + request2.onreadystatechange = function(){ + if (request2.readyState == 4) { + if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);} + } + } + + } + } + } + else { + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", host.concat(logoutURL), true, "logout", "logout"); + request.send(""); + request.onreadystatechange = function(){ + if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL); + } + } + } +}; + + +ROC_AUTH.remove = function (id) +{ + var element = document.getElementById(id); + element.outerHTML = ""; + delete element; + return; +}; + + + +$(document).ready(function() { + + if (typeof String.prototype.contains != 'function') { + String.prototype.contains = function (str){ + return this.indexOf(str) != -1; + }; + } + ROC_AUTH.progressive_loging(); + +}); + + +ROC_AUTH.progressive_loging = function () { + + ROC_AUTH.login_href(); +}; + + +$(document).keypress(function(e) { + if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) { + ROC_AUTH.login(); + } +}); + +ROC_AUTH.OnOneClick = function(event) { + event.preventDefault(); + if ( document.forms[0] === undefined ) { + ROC_AUTH.create_form(); + } + return false; +}; + +ROC_AUTH.login_href = function() { + var els = document.getElementsByTagName("a"); + for (var i = 0, l = els.length; i < l; i++) { + var el = els[i]; + if (el.href.contains("/basic_auth_login?destination")) { + loginURL = el.href; + var OneClick = el; + OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false); + } + } +}; + + +ROC_AUTH.create_form = function() { + + // Fetching HTML Elements in Variables by ID. + var createform = document.createElement('form'); // Create New Element Form + createform.setAttribute("action", ""); // Setting Action Attribute on Form + createform.setAttribute("method", "post"); // Setting Method Attribute on Form + $("body").append(createform); + + var heading = document.createElement('h2'); // Heading of Form + heading.innerHTML = "Login Form "; + createform.appendChild(heading); + + var line = document.createElement('hr'); // Giving Horizontal Row After Heading + createform.appendChild(line); + + var linebreak = document.createElement('br'); + createform.appendChild(linebreak); + + var namelabel = document.createElement('label'); // Create Label for Name Field + namelabel.innerHTML = "Username : "; // Set Field Labels + createform.appendChild(namelabel); + + var inputelement = document.createElement('input'); // Create Input Field for UserName + inputelement.setAttribute("type", "text"); + inputelement.setAttribute("name", "username"); + inputelement.setAttribute("required","required"); + createform.appendChild(inputelement); + + var linebreak = document.createElement('br'); + createform.appendChild(linebreak); + + var passwordlabel = document.createElement('label'); // Create Label for Password Field + passwordlabel.innerHTML = "Password : "; + createform.appendChild(passwordlabel); + + var passwordelement = document.createElement('input'); // Create Input Field for Password. + passwordelement.setAttribute("type", "password"); + passwordelement.setAttribute("name", "password"); + passwordelement.setAttribute("id", "password"); + passwordelement.setAttribute("required","required"); + createform.appendChild(passwordelement); + + + var passwordbreak = document.createElement('br'); + createform.appendChild(passwordbreak); + + + var submitelement = document.createElement('button'); // Append Submit Button + submitelement.setAttribute("type", "button"); + submitelement.setAttribute("onclick", "ROC_AUTH.login();"); + submitelement.innerHTML = "Sign In "; + createform.appendChild(submitelement); + +}; + + +var password = document.getElementById("password"); +var confirm_password = document.getElementById("confirm_password"); + +ROC_AUTH.validatePassword =function(){ + if ((password != null) && (confirm_password != null)) { + if(password.value != confirm_password.value) { + confirm_password.setCustomValidity("Passwords Don't Match"); + } else { + confirm_password.setCustomValidity(''); + } + } +} + +if ((password != null) && (confirm_password != null)) { + password.onchange = ROC_AUTH.validatePassword(); + confirm_password.onkeyup = ROC_AUTH.validatePassword; +} diff --git a/examples/demo/site/modules/session_auth/scripts/session_auth_table.sql b/examples/demo/site/modules/session_auth/scripts/session_auth_table.sql new file mode 100644 index 0000000..ada32db --- /dev/null +++ b/examples/demo/site/modules/session_auth/scripts/session_auth_table.sql @@ -0,0 +1,11 @@ + +CREATE TABLE session_auth ( + `uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0), + `access_token` TEXT NOT NULL, + `created` DATETIME NOT NULL, + CONSTRAINT `uid` + UNIQUE(`uid`), + CONSTRAINT `access_token` + UNIQUE(`access_token`) + ); + diff --git a/examples/demo/site/modules/session_auth/templates/block_login.tpl b/examples/demo/site/modules/session_auth/templates/block_login.tpl new file mode 100644 index 0000000..a344568 --- /dev/null +++ b/examples/demo/site/modules/session_auth/templates/block_login.tpl @@ -0,0 +1,37 @@ +
+ {unless isset="$user"} +

Login or Register

+
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ {/unless} + {if isset=$error} +
+
+

+ {$error/} +

+
+
+ {/if} +
diff --git a/examples/demo/src/demo_cms_execution.e b/examples/demo/src/demo_cms_execution.e index a3286d9..c73948f 100644 --- a/examples/demo/src/demo_cms_execution.e +++ b/examples/demo/src/demo_cms_execution.e @@ -89,6 +89,9 @@ feature -- CMS modules create {GOOGLE_CUSTOM_SEARCH_MODULE} m.make a_setup.register_module (m) + + create {CMS_SESSION_AUTH_MODULE} m.make + a_setup.register_module (m) end end diff --git a/modules/oauth20/cms_oauth_20_module.e b/modules/oauth20/cms_oauth_20_module.e index 1e96534..281d7a9 100644 --- a/modules/oauth20/cms_oauth_20_module.e +++ b/modules/oauth20/cms_oauth_20_module.e @@ -227,7 +227,7 @@ feature -- Hooks until lnk2 /= Void loop - if ic.item.location.same_string ("account/roc-logout") then + if ic.item.location.same_string ("account/roc-logout") or else ic.item.location.same_string ("basic_auth_logoff") then lnk2 := ic.item end end diff --git a/modules/openid/cms_openid_module.e b/modules/openid/cms_openid_module.e index e52184e..153305f 100644 --- a/modules/openid/cms_openid_module.e +++ b/modules/openid/cms_openid_module.e @@ -203,7 +203,7 @@ feature -- Hooks until lnk2 /= Void loop - if ic.item.location.same_string ("account/roc-logout") then + if ic.item.location.same_string ("account/roc-logout") or else ic.item.location.same_string ("basic_auth_logoff") then lnk2 := ic.item end end diff --git a/modules/openid/persitence/cms_openid_storage_sql.e b/modules/openid/persitence/cms_openid_storage_sql.e index f44c975..bb2f0d7 100644 --- a/modules/openid/persitence/cms_openid_storage_sql.e +++ b/modules/openid/persitence/cms_openid_storage_sql.e @@ -197,7 +197,7 @@ feature {NONE} -- User OpenID Sql_insert_openid: STRING = "INSERT INTO openid_items (uid, identity, created) VALUES (:uid, :identity, :utc_date);" - Sql_openid_consumers: STRING = "SELECT name FROM openid_consumers"; + Sql_openid_consumers: STRING = "SELECT name FROM openid_consumers;" feature {NONE} -- Consumer diff --git a/modules/session_auth/cms_session_api.e b/modules/session_auth/cms_session_api.e new file mode 100644 index 0000000..fd62dd2 --- /dev/null +++ b/modules/session_auth/cms_session_api.e @@ -0,0 +1,63 @@ +note + description: "API to manage CMS User session authentication" + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_API + + +inherit + CMS_MODULE_API + + REFACTORING_HELPER + +create {CMS_SESSION_AUTH_MODULE} + make_with_storage + +feature {NONE} -- Initialization + + make_with_storage (a_api: CMS_API; a_session_auth_storage: CMS_SESSION_AUTH_STORAGE_I) + -- Create an object with api `a_api' and storage `a_session_auth_storage'. + do + session_auth_storage := a_session_auth_storage + make (a_api) + ensure + session_auth_storage_set: session_auth_storage = a_session_auth_storage + end + +feature {CMS_MODULE} -- Access: User session storage. + + session_auth_storage: CMS_SESSION_AUTH_STORAGE_I + -- storage interface. + +feature -- Access + + user_by_session_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- Retrieve user by token `a_token', if any. + do + Result := session_auth_storage.user_by_session_token (a_token) + end + + has_user_token (a_user: CMS_USER): BOOLEAN + -- Has the user `a_user' and associated session token? + do + Result := session_auth_storage.has_user_token (a_user) + end + +feature -- Change User session + + new_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER;) + -- New user session for user `a_user' with token `a_token'. + do + session_auth_storage.new_user_session_auth (a_token, a_user) + end + + + update_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER ) + -- Update user session for user `a_user' with token `a_token'. + do + session_auth_storage.update_user_session_auth (a_token, a_user) + end + +end diff --git a/modules/session_auth/cms_session_auth-safe.ecf b/modules/session_auth/cms_session_auth-safe.ecf new file mode 100644 index 0000000..95f44a5 --- /dev/null +++ b/modules/session_auth/cms_session_auth-safe.ecf @@ -0,0 +1,28 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + + + + + + + + + diff --git a/modules/session_auth/cms_session_auth_module.e b/modules/session_auth/cms_session_auth_module.e new file mode 100644 index 0000000..52a8db8 --- /dev/null +++ b/modules/session_auth/cms_session_auth_module.e @@ -0,0 +1,351 @@ +note + description: "[ + This module allows the use Session Based Authentication using Cookies to restrict access + by looking up users in the given providers. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_AUTH_MODULE + +inherit + CMS_MODULE + rename + module_api as user_session_api + redefine + filters, + setup_hooks, + initialize, + install, + user_session_api + end + + + CMS_HOOK_AUTO_REGISTER + + CMS_HOOK_BLOCK + + CMS_HOOK_MENU_SYSTEM_ALTER + + CMS_HOOK_VALUE_TABLE_ALTER + + SHARED_LOGGER + + CMS_REQUEST_UTIL + +create + make + +feature {NONE} -- Initialization + + make + do + version := "1.0" + description := "Service to manage cookie based authentication" + package := "authentication" + add_dependency ({CMS_AUTHENTICATION_MODULE}) + end + +feature -- Access + + name: STRING = "session_auth" + + + +feature {CMS_API} -- Module Initialization + + initialize (a_api: CMS_API) + -- + local + l_session_auth_api: like user_session_api + l_user_auth_storage: CMS_SESSION_AUTH_STORAGE_I + do + Precursor (a_api) + + -- Storage initialization + if attached a_api.storage.as_sql_storage as l_storage_sql then + create {CMS_SESSION_AUTH_STORAGE_SQL} l_user_auth_storage.make (l_storage_sql) + else + -- FIXME: in case of NULL storage, should Current be disabled? + create {CMS_SESSION_AUTH_STORAGE_NULL} l_user_auth_storage + end + + -- API initialization + create l_session_auth_api.make_with_storage (a_api, l_user_auth_storage) + user_session_api := l_session_auth_api + ensure then + session_auth_api_set: user_session_api /= Void + end + +feature {CMS_API} -- Module management + + install (api: CMS_API) + local + l_consumers: LIST [STRING] + do + -- Schema + if attached api.storage.as_sql_storage as l_sql_storage then + if not l_sql_storage.sql_table_exists ("session_auth") then + --| Schema + l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("session_auth_table.sql")), Void) + + if l_sql_storage.has_error then + api.logger.put_error ("Could not initialize database for blog module", generating_type) + end + end + l_sql_storage.sql_finalize + Precursor {CMS_MODULE}(api) + end + end + +feature {CMS_API} -- Access: API + + user_session_api: detachable CMS_SESSION_API + -- + +feature -- Access: router + + setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + do + a_router.handle ("/account/roc-session-login", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login(a_api, ?, ?)), a_router.methods_head_get) + a_router.handle ("/account/roc-session-logout", create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout (a_api, ?, ?)), a_router.methods_get_post) + a_router.handle ("/account/login-with-session", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_login_with_session (a_api,user_session_api, ?, ?)), a_router.methods_get_post) + end + +feature -- Access: filter + + filters (a_api: CMS_API): detachable LIST [WSF_FILTER] + -- Possibly list of Filter's module. + do + create {ARRAYED_LIST [WSF_FILTER]} Result.make (1) + if attached user_session_api as l_session_api then + Result.extend (create {CMS_SESSION_AUTH_FILTER}.make (a_api, l_session_api)) + end + end + +feature {NONE} -- Implementation: routes + + handle_login (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + do + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + r.execute + end + + handle_logout (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + l_cookie: WSF_COOKIE + do + if + attached {WSF_STRING} req.cookie ({CMS_SESSION_CONSTANT}.session_auth_token) as l_cookie_token and then + attached {CMS_USER} current_user (req) as l_user + then + -- Logout Session + create l_cookie.make ({CMS_SESSION_CONSTANT}.session_auth_token, l_cookie_token.value) + l_cookie.set_path ("/") + l_cookie.set_max_age (-1) + res.add_cookie (l_cookie) + unset_current_user (req) + + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + r.set_status_code ({HTTP_CONSTANTS}.found) + r.set_redirection (req.absolute_script_url ("")) + r.execute + else + fixme (generator + ": missing else implementation in handle_logout!") + end + end + + handle_login_with_session (api: CMS_API; a_session_api: detachable CMS_SESSION_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + l_token: STRING + l_cookie: WSF_COOKIE + do + if + attached a_session_api as l_session_api and then + attached {WSF_STRING} req.form_parameter ("username") as l_username and then + attached {WSF_STRING} req.form_parameter ("password") as l_password and then + api.user_api.is_valid_credential (l_username.value, l_password.value) and then + attached api.user_api.user_by_name (l_username.value) as l_user + then + l_token := generate_token + if + a_session_api.has_user_token (l_user) + then + l_session_api.update_user_session_auth (l_token, l_user) + else + l_session_api.new_user_session_auth (l_token, l_user) + end + create l_cookie.make ({CMS_SESSION_CONSTANT}.session_auth_token, l_token) + l_cookie.set_max_age (60*60*24*360) + l_cookie.set_path ("/") + res.add_cookie (l_cookie) + set_current_user (req, l_user) + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + r.set_redirection (req.absolute_script_url ("")) + r.execute + else + create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) + if attached template_block ("login", r) as l_tpl_block then + if attached {WSF_STRING} req.form_parameter ("username") as l_username then + l_tpl_block.set_value (l_username.value, "username") + end + l_tpl_block.set_value ("Wrong: Username or password ", "error") + r.add_block (l_tpl_block, "content") + end + r.execute + end + end + +feature -- Hooks configuration + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- Module hooks configuration. + do + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_value_table_alter_hook (Current) + end + +feature -- Hooks + + value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE) + -- + do + if + attached a_response.user as u and then + attached {WSF_STRING} a_response.request.cookie ({CMS_SESSION_CONSTANT}.session_auth_token) + then + a_value.force ("account/roc-session-logout", "auth_login_strategy") + end + + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + -- Hook execution on collection of menu contained by `a_menu_system' + -- for related response `a_response'. + local + lnk: CMS_LOCAL_LINK + lnk2: detachable CMS_LINK + do + if + attached a_response.user as u and then + attached {WSF_STRING} a_response.request.cookie ({CMS_SESSION_CONSTANT}.session_auth_token) + then + across + a_menu_system.primary_menu.items as ic + until + lnk2 /= Void + loop + if ic.item.location.same_string ("account/roc-logout") or else ic.item.location.same_string ("basic_auth_logoff") then + lnk2 := ic.item + end + end + if lnk2 /= Void then + a_menu_system.primary_menu.remove (lnk2) + end + create lnk.make ("Logout", "account/roc-session-logout" ) + a_menu_system.primary_menu.extend (lnk) + else + if a_response.location.starts_with ("account/") then + create lnk.make ("Session", "account/roc-session-login") + a_response.add_to_primary_tabs (lnk) + end + end + end + + block_list: ITERABLE [like {CMS_BLOCK}.name] + local + l_string: STRING + do + Result := <<"login">> + debug ("roc") + create l_string.make_empty + across + Result as ic + loop + l_string.append (ic.item) + l_string.append_character (' ') + end + write_debug_log (generator + ".block_list:" + l_string ) + end + end + + get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) + do + if + a_block_id.is_case_insensitive_equal_general ("login") and then + a_response.location.starts_with ("account/roc-session-login") + then + get_block_view_login (a_block_id, a_response) + end + end + +feature {NONE} -- Helpers + + template_block (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE): detachable CMS_SMARTY_TEMPLATE_BLOCK + -- Smarty content block for `a_block_id' + local + p: detachable PATH + do + create p.make_from_string ("templates") + p := p.extended ("block_").appended (a_block_id).appended_with_extension ("tpl") + + p := a_response.api.module_theme_resource_location (Current, p) + if p /= Void then + if attached p.entry as e then + create Result.make (a_block_id, Void, p.parent, e) + else + create Result.make (a_block_id, Void, p.parent, p) + end + end + end + +feature {NONE} -- Block views + + get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) + local + vals: CMS_VALUE_TABLE + do + if attached template_block (a_block_id, a_response) as l_tpl_block then + create vals.make (1) + -- add the variable to the block + value_table_alter (vals, a_response) + across + vals as ic + loop + l_tpl_block.set_value (ic.item, ic.key) + end + a_response.add_block (l_tpl_block, "content") + else + debug ("cms") + a_response.add_warning_message ("Error with block [" + a_block_id + "]") + end + end + end + + + generate_token: STRING + -- Generate token to use in a Session. + local + l_token: STRING + l_security: CMS_TOKEN_GENERATOR + l_encode: URL_ENCODER + do + create l_security + l_token := l_security.token + create l_encode + from until l_token.same_string (l_encode.encoded_string (l_token)) loop + -- Loop ensure that we have a security token that does not contain characters that need encoding. + -- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token + -- but the user will need to use an unencoded token if activation has to be done manually. + l_token := l_security.token + end + Result := l_token + end +end diff --git a/modules/session_auth/cms_session_constant.e b/modules/session_auth/cms_session_constant.e new file mode 100644 index 0000000..8d44501 --- /dev/null +++ b/modules/session_auth/cms_session_constant.e @@ -0,0 +1,13 @@ +note + description: "Summary description for {CMS_SESSION_CONSTANT}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_CONSTANT + + +feature + session_auth_token: STRING = "EWF_ROC_SESSION_AUTH_TOKEN_" + -- Name of Cookie used to keep the session info. +end diff --git a/modules/session_auth/filter/cms_session_auth_filter.e b/modules/session_auth/filter/cms_session_auth_filter.e new file mode 100644 index 0000000..dd96337 --- /dev/null +++ b/modules/session_auth/filter/cms_session_auth_filter.e @@ -0,0 +1,55 @@ +note + description: "[ + Processes a HTTP request's checking Session cookies, putting the result into the execution variable user. + ]" + date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $" + revision: "$Revision: 96616 $" + +class + CMS_SESSION_AUTH_FILTER + +inherit + WSF_URI_TEMPLATE_HANDLER + + CMS_HANDLER + rename + make as make_handler + end + + WSF_FILTER + +create + make + +feature {NONE} -- Initialization + + make (a_api: CMS_API; a_session_oauth_api: CMS_SESSION_API) + do + make_handler (a_api) + session_oauth_api := a_session_oauth_api + end + + session_oauth_api: CMS_SESSION_API + +feature -- Basic operations + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute the filter. + do + api.logger.put_debug (generator + ".execute ", Void) + -- A valid user + if + attached {WSF_STRING} req.cookie ({CMS_SESSION_CONSTANT}.session_auth_token) as l_roc_auth_session_token + then + if attached session_oauth_api.user_by_session_token (l_roc_auth_session_token.value) as l_user then + set_current_user (req, l_user) + else + api.logger.put_error (generator + ".execute login_valid failed for: " + l_roc_auth_session_token.value , Void) + end + else + api.logger.put_debug (generator + ".execute without authentication", Void) + end + execute_next (req, res) + end + +end diff --git a/modules/session_auth/handler/cms_session_auth_logoff_handler.e b/modules/session_auth/handler/cms_session_auth_logoff_handler.e new file mode 100644 index 0000000..36a4e19 --- /dev/null +++ b/modules/session_auth/handler/cms_session_auth_logoff_handler.e @@ -0,0 +1,132 @@ +note + description: "Summary description for {CMS_SESSION_AUTH_LOGOFF_HANDLER}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_AUTH_LOGOFF_HANDLER + +inherit + CMS_HANDLER + + WSF_URI_HANDLER + rename + execute as uri_execute, + new_mapping as new_uri_mapping + end + + WSF_RESOURCE_HANDLER_HELPER + redefine + do_get + end + + REFACTORING_HELPER + +create + make + +feature -- execute + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler. + do + execute_methods (req, res) + end + + uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler. + do + execute_methods (req, res) + end + +feature -- HTTP Methods + + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) + -- + local + l_page: CMS_RESPONSE + l_url: STRING + i: INTEGER + l_message: STRING + do + api.logger.put_information (generator + ".do_get Processing basic auth logoff", Void) + if attached req.query_parameter ("prompt") as l_prompt then + unset_current_user (req) + send_access_denied_message (res) + else + create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) + unset_current_user (req) + l_page.set_status_code ({HTTP_STATUS_CODE}.unauthorized) -- Note: can not use {HTTP_STATUS_CODE}.unauthorized for redirection + l_url := req.absolute_script_url ("") + i := l_url.substring_index ("://", 1) + if i > 0 then + -- Note: this is a hack to have the logout effective on various browser + -- (firefox requires this). + l_url.replace_substring ("://_logout_basic_auth_@", i, i + 2) + end + if + attached req.http_user_agent as l_user_agent and then + browser_name (l_user_agent).is_case_insensitive_equal_general ("Firefox") + then + -- Set status to refirect + -- and redirect to the host page. + l_page.set_status_code ({HTTP_STATUS_CODE}.found) + l_page.set_redirection (l_url) + end + create l_message.make_from_string (logout_message) + l_message.replace_substring_all ("$site_login", req.absolute_script_url ("/account/roc-login")) + l_message.replace_substring_all ("$site_home", req.absolute_script_url ("")) + l_page.set_main_content (l_message) + l_page.execute + end + end + + + browser_name (a_user_agent: READABLE_STRING_8): READABLE_STRING_32 + -- Browser name. + -- Must contain Must not contain + -- Firefox Firefox/xyz Seamonkey/xyz + -- Seamonkey Seamonkey/xyz + -- Chrome Chrome/xyz Chromium/xyz + -- Chromium Chromium/xyz + -- Safari Safari/xyz Chrome/xyz + -- Chromium/xyz + -- Opera OPR/xyz [1] + -- Opera/xyz [2] + -- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format + + do + if + a_user_agent.has_substring ("Firefox") and then + not a_user_agent.has_substring ("Seamonkey") + then + Result := "Firefox" + elseif a_user_agent.has_substring ("Seamonkey") then + Result := "Seamonkey" + elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then + Result := "Chrome" + elseif a_user_agent.has_substring ("Chromium") then + Result := "Chromiun" + elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then + Result := "Safari" + elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then + Result := "Opera" + elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then + Result := "Internet Explorer" + else + Result := "Unknown" + end + end + + + feature {NONE}-- Lougout Message + + logout_message: STRING = "[ +
+

You are now signed out

+

You can log in again, or go to the front page.

+
+ ]" + + +end diff --git a/modules/session_auth/persistence/cms_session_auth_storage_i.e b/modules/session_auth/persistence/cms_session_auth_storage_i.e new file mode 100644 index 0000000..f40b5bf --- /dev/null +++ b/modules/session_auth/persistence/cms_session_auth_storage_i.e @@ -0,0 +1,46 @@ +note + description: "[ + API to handle OAUTH storage + ]" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_SESSION_AUTH_STORAGE_I + +inherit + SHARED_LOGGER + +feature -- Error Handling + + error_handler: ERROR_HANDLER + -- Error handler. + deferred + end + +feature -- Access: Users + + user_by_session_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- Retrieve user by token `a_token', if any. + deferred + end + + has_user_token (a_user: CMS_USER): BOOLEAN + -- Has the user `a_user' and associated session token? + deferred + end + + +feature -- Change User session + + new_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER;) + -- New user session for user `a_user' with token `a_token'. + deferred + end + + + update_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER ) + -- Update user session for user `a_user' with token `a_token'. + deferred + end +end diff --git a/modules/session_auth/persistence/cms_session_auth_storage_null.e b/modules/session_auth/persistence/cms_session_auth_storage_null.e new file mode 100644 index 0000000..ff2da97 --- /dev/null +++ b/modules/session_auth/persistence/cms_session_auth_storage_null.e @@ -0,0 +1,47 @@ +note + description: "Summary description for {CMS_SESSION_AUTH_STORAGE_NULL}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_AUTH_STORAGE_NULL + +inherit + + CMS_SESSION_AUTH_STORAGE_I + + +feature -- Error handler + + error_handler: ERROR_HANDLER + -- Error handler. + do + create Result.make + end + +feature -- Access + + user_by_session_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- Retrieve user by token `a_token', if any. + do + end + + has_user_token (a_user: CMS_USER): BOOLEAN + -- Has the user `a_user' and associated session token? + do + end + +feature -- Change User session + + new_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER;) + -- New user session for user `a_user' with token `a_token'. + do + end + + + update_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER ) + -- Update user session for user `a_user' with token `a_token'. + do + end + +end diff --git a/modules/session_auth/persistence/cms_session_auth_storage_sql.e b/modules/session_auth/persistence/cms_session_auth_storage_sql.e new file mode 100644 index 0000000..a6b5d26 --- /dev/null +++ b/modules/session_auth/persistence/cms_session_auth_storage_sql.e @@ -0,0 +1,169 @@ +note + description: "Summary description for {CMS_SESSION_AUTH_STORAGE_SQL}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_AUTH_STORAGE_SQL + +inherit + CMS_SESSION_AUTH_STORAGE_I + + CMS_PROXY_STORAGE_SQL + + CMS_SESSION_AUTH_STORAGE_I + + CMS_STORAGE_SQL_I + + REFACTORING_HELPER + +create + make + +feature -- Access User + + user_by_session_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- Retrieve user by token `a_token', if any. + local + l_parameters: STRING_TABLE [detachable ANY] + l_string: STRING + do + error_handler.reset + write_information_log (generator + ".user_by_session_token") + create l_parameters.make (1) + l_parameters.put (a_token, "token") + sql_insert (Select_user_by_token, l_parameters) + if not has_error and not sql_after then + Result := fetch_user + sql_forth + if not sql_after then + check no_more_than_one: False end + Result := Void + end + end + sql_finalize + end + + + has_user_token (a_user: CMS_USER): BOOLEAN + -- Has the user `a_user' and associated session token? + local + l_parameters: STRING_TABLE [detachable ANY] + l_string: STRING + do + error_handler.reset + write_information_log (generator + ".has_user_token") + create l_parameters.make (1) + l_parameters.put (a_user.id, "uid") + sql_insert (Select_user_token, l_parameters) + if not has_error and not sql_after then + if sql_read_integer_64 (1) = 1 then + Result := True + else + Result := False + end + end + sql_finalize + end + + + +feature -- Change User token + + new_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER;) + -- Add a new user with oauth2 authentication. + -- . + local + l_parameters: STRING_TABLE [detachable ANY] + l_string: STRING + do + error_handler.reset + sql_begin_transaction + + write_information_log (generator + ".new_user_session") + create l_parameters.make (3) + l_parameters.put (a_user.id, "uid") + l_parameters.put (a_token, "token") + l_parameters.put (create {DATE_TIME}.make_now_utc, "utc_date") + + sql_insert (sql_insert_session_auth, l_parameters) + sql_commit_transaction + sql_finalize + end + + update_user_session_auth (a_token: READABLE_STRING_GENERAL; a_user: CMS_USER ) + -- + local + l_parameters: STRING_TABLE [detachable ANY] + l_string: STRING + do + error_handler.reset + sql_begin_transaction + + write_information_log (generator + ".update_user_session_auth") + create l_parameters.make (3) + l_parameters.put (a_user.id, "uid") + l_parameters.put (a_token, "token") + l_parameters.put (create {DATE_TIME}.make_now_utc, "utc_date") + + + sql_modify (sql_update_session_auth, l_parameters) + sql_commit_transaction + sql_finalize + end + + +feature {NONE} -- Implementation + +fetch_user: detachable CMS_USER + local + l_id: INTEGER_64 + l_name: detachable READABLE_STRING_32 + do + if attached sql_read_integer_64 (1) as i then + l_id := i + end + if attached sql_read_string_32 (2) as s and then not s.is_whitespace then + l_name := s + end + + if l_name /= Void then + create Result.make (l_name) + if l_id > 0 then + Result.set_id (l_id) + end + elseif l_id > 0 then + create Result.make_with_id (l_id) + end + + if Result /= Void then + if attached sql_read_string (3) as l_password then + -- FIXME: should we return the password here ??? + Result.set_hashed_password (l_password) + end + if attached sql_read_string (5) as l_email then + Result.set_email (l_email) + end + if attached sql_read_integer_32 (6) as l_status then + Result.set_status (l_status) + end + else + check expected_valid_user: False end + end + end + + +feature {NONE} -- SQL statements + + Select_user_by_token: STRING = "SELECT u.* FROM users as u JOIN session_auth as og ON og.uid = u.uid and og.access_token = :token;" + --| FIXME: replace the u.* by a list of field names, to avoid breaking `featch_user' if two fieds are swiped. + + Sql_insert_session_auth: STRING = "INSERT INTO session_auth (uid, access_token, created) VALUES (:uid, :token, :utc_date);" + + + Sql_update_session_auth: STRING = "UPDATE session_auth SET access_token = :token, created = :utc_date WHERE uid =:uid;" + + + Select_user_token: STRING = "SELECT COUNT(*) FROM session_auth where uid = :uid;" + +end diff --git a/modules/session_auth/site/cms_token_generator.e b/modules/session_auth/site/cms_token_generator.e new file mode 100644 index 0000000..ba1adb8 --- /dev/null +++ b/modules/session_auth/site/cms_token_generator.e @@ -0,0 +1,153 @@ +note + description: "Provides security routine helpers" + date: "$Date$" + revision: "$Revision$" + +class + CMS_TOKEN_GENERATOR + +inherit + + REFACTORING_HELPER + +feature -- Access + + token: STRING + -- Cryptographic random base 64 string. + do + Result := salt_with_size (16) + -- Remove trailing equal sign + Result.keep_head (Result.count - 2) + end + + salt: STRING + -- Cryptographic random number of 16 bytes. + do + Result := salt_with_size (16) + end + + password: STRING + -- Cryptographic random password of 10 bytes. + do + Result := salt_with_size (10) + -- Remove trailing equal signs + Result.keep_head (Result.count - 2) + end + + password_hash (a_password, a_salt: STRING): STRING + -- Password hash based on password `a_password' and salt value `a_salt'. + do + Result := sha1_string (a_password + a_salt ) + end + +feature {NONE} -- Implementation + + salt_with_size (a_val: INTEGER): STRING + -- Return a salt with size `a_val'. + local + l_salt: SALT_XOR_SHIFT_64_GENERATOR + l_array: ARRAY [INTEGER_8] + i: INTEGER + do + create l_salt.make (a_val) + create l_array.make_empty + i := 1 + across + l_salt.new_sequence as c + loop + l_array.force (c.item.as_integer_8, i) + i := i + 1 + end + Result := encode_base_64 (l_array) + end + + sha1_string (a_str: STRING): STRING + -- SHA1 diggest of `a_str'. + do + sha1.update_from_string (a_str) + Result := sha1.digest_as_string + sha1.reset + end + + sha1: SHA1 + -- Create a SHA1 object. + once + create Result.make + end + +feature -- Encoding + + + encode_base_64 (bytes: SPECIAL [INTEGER_8]): STRING_8 + -- Encodes a byte array into a STRING doing base64 encoding. + local + l_output: SPECIAL [INTEGER_8] + l_remaining: INTEGER + i, ptr: INTEGER + char: CHARACTER + do + to_implement ("Check existing code to do that!!!.") + create l_output.make_filled (0, ((bytes.count + 2) // 3) * 4) + l_remaining := bytes.count + from + i := 0 + ptr := 0 + until + l_remaining <= 3 + loop + l_output [ptr] := encode_value (bytes [i] |>> 2) + ptr := ptr + 1 + l_output [ptr] := encode_value (((bytes [i] & 0x3) |<< 4) | ((bytes [i + 1] |>> 4) & 0xF)) + ptr := ptr + 1 + l_output [ptr] := encode_value (((bytes [i + 1] & 0xF) |<< 2) | ((bytes [i + 2] |>> 6) & 0x3)) + ptr := ptr + 1 + l_output [ptr] := encode_value (bytes [i + 2] & 0x3F) + ptr := ptr + 1 + l_remaining := l_remaining - 3 + i := i + 3 + end + -- encode when exactly 1 element (left) to encode + char := '=' + if l_remaining = 1 then + l_output [ptr] := encode_value (bytes [i] |>> 2) + ptr := ptr + 1 + l_output [ptr] := encode_value (((bytes [i]) & 0x3) |<< 4) + ptr := ptr + 1 + l_output [ptr] := char.code.as_integer_8 + ptr := ptr + 1 + l_output [ptr] := char.code.as_integer_8 + ptr := ptr + 1 + end + + -- encode when exactly 2 elements (left) to encode + if l_remaining = 2 then + l_output [ptr] := encode_value (bytes [i] |>> 2) + ptr := ptr + 1 + l_output [ptr] := encode_value (((bytes [i] & 0x3) |<< 4) | ((bytes [i + 1] |>> 4) & 0xF)); + ptr := ptr + 1 + l_output [ptr] := encode_value ((bytes [i + 1] & 0xF) |<< 2); + ptr := ptr + 1 + l_output [ptr] := char.code.as_integer_8 + ptr := ptr + 1 + end + Result := "" + across + l_output as elem + loop + Result.append_character (elem.item.to_character_8) + end + end + + base64_map: SPECIAL [CHARACTER_8] + -- Table for Base64 encoding. + once + Result := ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").area + end + + encode_value (i: INTEGER_8): INTEGER_8 + -- Encode `i'. + do + Result := base64_map [i & 0x3F].code.as_integer_8 + end + +end diff --git a/modules/session_auth/site/files/js/roc_basic_auth.js b/modules/session_auth/site/files/js/roc_basic_auth.js new file mode 100644 index 0000000..467bcd4 --- /dev/null +++ b/modules/session_auth/site/files/js/roc_basic_auth.js @@ -0,0 +1,325 @@ +var ROC_AUTH = ROC_AUTH || { }; + +var loginURL = "/basic_auth_login"; +var logoutURL = "/basic_auth_logoff"; + +var userAgent = navigator.userAgent.toLowerCase(); +var firstLogIn = true; + +ROC_AUTH.login = function() { + var form = document.forms['cms_basic_auth']; + var username = form.username.value; + var password = form.password.value; + //var host = form.host.value; + var origin = window.location.origin + window.location.pathname; + var _login = function(){ + + + if (document.getElementById('myModalFormId') !== null ) { + ROC_AUTH.remove ('myModalFormId'); + } + + + if (username === "" || password === "") { + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + } + }else{ + + //Instantiate HTTP Request + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", loginURL, true, username, password); + request.send(null); + + //Process Response + request.onreadystatechange = function(){ + if (request.readyState == 4) { + if (request.status==200) { + delete form; + window.location=window.location.origin; + } + else{ + if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){ + } + + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + } + + } + } + } + } + } + + var userAgent = navigator.userAgent.toLowerCase(); + if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + if (firstLogIn) _login(); + else logoff(_login); + } + else{ + _login(); + } + + if (firstLogIn) firstLogIn = false; +}; + + +ROC_AUTH.login_with_redirect = function() { + var form = document.forms[2]; + var username = form.username.value; + var password = form.password.value; + var host = form.host.value; + var _login = function(){ + + var redirectURL = form.redirect && form.redirect.value || ""; + + + $("#imgProgressRedirect").show(); + + if (document.getElementById('myModalFormId') !== null ) { + ROC_AUTH.remove ('myModalFormId'); + } + + + if (username === "" || password === "") { + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + $("#imgProgressRedirect").hide(); + } + }else{ + + //Instantiate HTTP Request + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", host.concat(loginURL), true, username, password); + request.send(null); + + //Process Response + request.onreadystatechange = function(){ + if (request.readyState == 4) { + if (request.status==200) { + if (redirectURL === "") { + window.location=host.concat("/"); + } else { + window.location=host.concat(redirectURL); + } + + } + else{ + if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){ + } + + if (document.getElementById('myModalFormId') === null ) { + var newdiv = document.createElement('div'); + newdiv.innerHTML = "
Invalid Credentials
"; + newdiv.id = 'myModalFormId'; + $(".primary-tabs").append(newdiv); + $("#imgProgressRedirect").hide(); + } + + } + } + } + } + } + + var userAgent = navigator.userAgent.toLowerCase(); + if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + if (firstLogIn) _login(); + else logoff(_login); + } + else{ + _login(); + } + + if (firstLogIn) firstLogIn = false; +}; + + +ROC_AUTH.getQueryParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " ")); +} + +ROC_AUTH.logoff = function(callback){ + var form = document.forms[0]; + var host = form.host.value; + + if (userAgent.indexOf("msie") != -1) { + document.execCommand("ClearAuthenticationCache"); + } + else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number + + var request1 = new XMLHttpRequest(); + var request2 = new XMLHttpRequest(); + + //Logout. Tell the server not to return the "WWW-Authenticate" header + request1.open("GET", host.concat(logoutURL) + "?prompt=false", true); + request1.send(""); + request1.onreadystatechange = function(){ + if (request1.readyState == 4) { + + //Sign in with dummy credentials to clear the auth cache + request2.open("GET", host.concat(logoutURL), true, "logout", "logout"); + request2.send(""); + + request2.onreadystatechange = function(){ + if (request2.readyState == 4) { + if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);} + } + } + + } + } + } + else { + var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); + request.open("GET", host.concat(logoutURL), true, "logout", "logout"); + request.send(""); + request.onreadystatechange = function(){ + if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL); + } + } + } +}; + + +ROC_AUTH.remove = function (id) +{ + var element = document.getElementById(id); + element.outerHTML = ""; + delete element; + return; +}; + + + +$(document).ready(function() { + + if (typeof String.prototype.contains != 'function') { + String.prototype.contains = function (str){ + return this.indexOf(str) != -1; + }; + } + ROC_AUTH.progressive_loging(); + +}); + + +ROC_AUTH.progressive_loging = function () { + + ROC_AUTH.login_href(); +}; + + +$(document).keypress(function(e) { + if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) { + ROC_AUTH.login(); + } +}); + +ROC_AUTH.OnOneClick = function(event) { + event.preventDefault(); + if ( document.forms[0] === undefined ) { + ROC_AUTH.create_form(); + } + return false; +}; + +ROC_AUTH.login_href = function() { + var els = document.getElementsByTagName("a"); + for (var i = 0, l = els.length; i < l; i++) { + var el = els[i]; + if (el.href.contains("/basic_auth_login?destination")) { + loginURL = el.href; + var OneClick = el; + OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false); + } + } +}; + + +ROC_AUTH.create_form = function() { + + // Fetching HTML Elements in Variables by ID. + var createform = document.createElement('form'); // Create New Element Form + createform.setAttribute("action", ""); // Setting Action Attribute on Form + createform.setAttribute("method", "post"); // Setting Method Attribute on Form + $("body").append(createform); + + var heading = document.createElement('h2'); // Heading of Form + heading.innerHTML = "Login Form "; + createform.appendChild(heading); + + var line = document.createElement('hr'); // Giving Horizontal Row After Heading + createform.appendChild(line); + + var linebreak = document.createElement('br'); + createform.appendChild(linebreak); + + var namelabel = document.createElement('label'); // Create Label for Name Field + namelabel.innerHTML = "Username : "; // Set Field Labels + createform.appendChild(namelabel); + + var inputelement = document.createElement('input'); // Create Input Field for UserName + inputelement.setAttribute("type", "text"); + inputelement.setAttribute("name", "username"); + inputelement.setAttribute("required","required"); + createform.appendChild(inputelement); + + var linebreak = document.createElement('br'); + createform.appendChild(linebreak); + + var passwordlabel = document.createElement('label'); // Create Label for Password Field + passwordlabel.innerHTML = "Password : "; + createform.appendChild(passwordlabel); + + var passwordelement = document.createElement('input'); // Create Input Field for Password. + passwordelement.setAttribute("type", "password"); + passwordelement.setAttribute("name", "password"); + passwordelement.setAttribute("id", "password"); + passwordelement.setAttribute("required","required"); + createform.appendChild(passwordelement); + + + var passwordbreak = document.createElement('br'); + createform.appendChild(passwordbreak); + + + var submitelement = document.createElement('button'); // Append Submit Button + submitelement.setAttribute("type", "button"); + submitelement.setAttribute("onclick", "ROC_AUTH.login();"); + submitelement.innerHTML = "Sign In "; + createform.appendChild(submitelement); + +}; + + +var password = document.getElementById("password"); +var confirm_password = document.getElementById("confirm_password"); + +ROC_AUTH.validatePassword =function(){ + if ((password != null) && (confirm_password != null)) { + if(password.value != confirm_password.value) { + confirm_password.setCustomValidity("Passwords Don't Match"); + } else { + confirm_password.setCustomValidity(''); + } + } +} + +if ((password != null) && (confirm_password != null)) { + password.onchange = ROC_AUTH.validatePassword(); + confirm_password.onkeyup = ROC_AUTH.validatePassword; +} diff --git a/modules/session_auth/site/scripts/session_auth_table.sql.tpl b/modules/session_auth/site/scripts/session_auth_table.sql.tpl new file mode 100644 index 0000000..ada32db --- /dev/null +++ b/modules/session_auth/site/scripts/session_auth_table.sql.tpl @@ -0,0 +1,11 @@ + +CREATE TABLE session_auth ( + `uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0), + `access_token` TEXT NOT NULL, + `created` DATETIME NOT NULL, + CONSTRAINT `uid` + UNIQUE(`uid`), + CONSTRAINT `access_token` + UNIQUE(`access_token`) + ); + diff --git a/modules/session_auth/site/templates/block_login.tpl b/modules/session_auth/site/templates/block_login.tpl new file mode 100644 index 0000000..a344568 --- /dev/null +++ b/modules/session_auth/site/templates/block_login.tpl @@ -0,0 +1,37 @@ +
+ {unless isset="$user"} +

Login or Register

+
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ {/unless} + {if isset=$error} +
+
+

+ {$error/} +

+
+
+ {/if} +