Skip to content

Commit

Permalink
Added SSO Codes
Browse files Browse the repository at this point in the history
Added Single Sign on Codes and Example
  • Loading branch information
maanas committed May 19, 2013
1 parent 176fb79 commit 6d62770
Show file tree
Hide file tree
Showing 98 changed files with 16,217 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ This will result in access being granted and the endpoint request is processed
#### Invalid Credentials
This will result in redirection for authentication


#### Restriction on username and password
The support only aplha user name and alpha password. Need to add regex to allow some special charactors.

## Project Roadmap
Integrate SAML into the project so that the SSO can work at par with other commercial grade single sign on solutions but at much faster and efficiently.
Expand Down
28 changes: 28 additions & 0 deletions nginx-conf/example.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
server
{
server_name .maanas.co;

access_log /home/example/log/agms.maanas.co.access.log;

error_log /home/example/log/agms.maanas.co.error.log;

root /home/example/projects;

index index.php index.html index.htm;

location / {
}

location /apps/example {
default_type 'text/plain';
# Add this to enable SSO on any location
error_page 401 /401;
# Specify the app which validate the access
set $app 'example';
access_by_lua_file /opt/nginx/conf/sso/sso.lua;
# Any other request parameters
}



}
53 changes: 53 additions & 0 deletions nginx-conf/login.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
-- login.lua
-- Login Module in Lua

-- TODO Introduce CSFR token in login form and redirection to basic page, detect json request

-- This is only a POST Endpoint
if ngx.req.get_method() == "POST" then

-- Read request body
ngx.req.read_body()
local args = ngx.req.get_post_args()
-- Sanity Check for username and password
if string.match(args["username"],"%W") or string.match(args["password"],"%W") then
-- Improper charactors detected
ngx.exit(ngx.HTTP_BAD_REQUEST)
else
-- Fire the sql to check for
local resp = ngx.location.capture("/sso/login?username="..args['username'].."&hash="..args['password'])
_, _, no, uid, data = string.find(resp.body, [[%[%{"no":(%d+),"uid":(%d+),"data":"([%w ]+)"%}%]%s*]])
if tonumber(no) == 1 then
-- valid user, Generate a session_token
resp = ngx.location.capture("/sso/token")
_, _, token = string.find(resp.body, [[%[%{"token":"(%w+)"%}%]%s*]])

-- Delete all stale session information for this uid
resp = ngx.location.capture("/sso/session/stale?uid="..uid)
_, _, errcode, affected_rows = string.find(resp.body, [[%{"errcode":(%d+),"affected_rows":(%d+)%}%s*]])

-- Save token in session
resp = ngx.location.capture("/sso/session/add?token="..token.."&uid="..uid)
_, _, errcode, affected_rows = string.find(resp.body, [[%{"errcode":(%d+),"affected_rows":(%d+)%}%s*]])

if tonumber(errcode) == 0 and tonumber(affected_rows) == 1 then
-- Token set in database, set cookiee
local expires = tonumber(ngx.time()) + 3600
ngx.header["Set-Cookie"] = "uid="..uid..";path=/;domain=.maanas.co;expires="..ngx.cookie_time(expires)
ngx.header["Set-Cookie"] = "session_token="..token..";path=/;domain=.maanas.co;expires="..ngx.cookie_time(expires)
-- Redirect to Incoming Page
if (ngx.var.cookie_AGMSRedirectBack ~= nil) then
return ngx.redirect(ngx.var.cookie_AGMSRedirectBack)
else
return ngx.redirect("http://sso.maanas.co/sso/welcome.html")
end
else
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
else
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
end
else
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
25 changes: 25 additions & 0 deletions nginx-conf/logout.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- login.lua
-- Login Module in Lua

-- TODO Introduce CSFR token in login form and redirection to basic page, detect json request
-- Check the session token exist
if ngx.var.cookie_session_token then
-- Sanity Check for session_token
if string.match(ngx.var.cookie_session_token,"%W") then
-- We got a poisioned cookie
ngx.exit(ngx.HTTP_BAD_REQUEST)
else
-- Destroy token in session
ngx.location.capture("/sso/session/delete?token="..ngx.var.cookie_session_token)
-- Delete all cookie
ngx.header["Set-Cookie"] = "uid=deleted;path=/;domain=.maanas.co;expires=Thu, 01-Jan-1970 00:00:01 GMT"
ngx.header["Set-Cookie"] = "session_token=deleted;path=/;domain=.maanas.co;expires=Thu, 01-Jan-1970 00:00:01 GMT"
-- Save the logout URl so that we can come back to this page
ngx.header["Set-Cookie"] = "AGMSRedirectBack=http://"..ngx.var.host..ngx.var.uri..";path=/;domain=.maanas.co;Max-Age=120"
-- Redirect to login form
return ngx.redirect("http://sso.maanas.co/sso")
end
else
return ngx.redirect("http://sso.maanas.co/sso")

end
8 changes: 8 additions & 0 deletions nginx-conf/ngnix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Add this in ngnix.conf inside http {}
# Drizzle sso
upstream sso {
drizzle_server 127.0.0.1:3306 dbname=sso
password=database-password user=sso_dba protocol=mysql;
}
# Load the sso.conf file
include /opt/nginx/conf/sso/sso.conf;
221 changes: 221 additions & 0 deletions nginx-conf/sso.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
### Single Sign On Endpoints ###
# Cookie to be valid for whole domain on all sub-domaons #


# Token Endpoint to generate session and access token

location = /sso/token {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set $token_sql 'SELECT SHA2(UUID(), 256) AS token' ;

drizzle_query $token_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s
}


location = /sso/session {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $token $cookie_session_token;
set_quote_sql_str $app $arg_app;
set $session_sql 'SELECT 1 AS no, IFNULL(s_uid, 0) AS uid, IFNULL(s_data,"") as data FROM session, app WHERE s_uid = ap_uid AND ap_app = $app AND ap_enabled = 1 AND s_token = $token AND UNIX_TIMESTAMP() - 3600 < s_lastaccess LIMIT 1' ;

drizzle_query $session_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}

location = /sso/session/add {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $token $arg_token;
set_quote_sql_str $uid $arg_uid;

set $add_sql 'INSERT INTO session(s_token, s_uid, s_dateadded, s_lastaccess) VALUES ($token, $uid, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())' ;

drizzle_query $add_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}

location = /sso/session/update {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $token $arg_token;

set $add_sql 'UPDATE session SET s_lastaccess = UNIX_TIMESTAMP() WHERE s_token = $token' ;

drizzle_query $add_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}


location = /sso/session/delete {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $token $arg_token;

set $delete_sql 'DELETE FROM session WHERE s_token = $token' ;
echo $delete_sql;
drizzle_query $delete_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}

location = /sso/session/stale {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $uid $arg_uid;

set $delete_sql 'DELETE FROM session WHERE s_uid = $uid AND s_lastaccess < (UNIX_TIMESTAMP() - 7200) ';

drizzle_query $delete_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}

location = /sso/login {
internal; # Internal Location Called from sub request only
default_type 'text/plain';

set_quote_sql_str $username $arg_username;
set_quote_sql_str $hash $arg_hash;

set $login_sql 'SELECT 1 as no, u_id as uid, CONCAT(u_firstname, " ", u_lastname) as data FROM user WHERE u_username = $username AND u_hash = SHA2($hash, 256) ';

drizzle_query $login_sql;
drizzle_pass sso;

rds_json on;

drizzle_connect_timeout 500ms; # default 60s
drizzle_send_query_timeout 2s; # default 60s
drizzle_recv_cols_timeout 1s; # default 60s
drizzle_recv_rows_timeout 1s; # default 60s

}


### External Locations

location = /login {
# MIME type determined by default_type:
default_type 'text/plain';

access_by_lua_file /opt/nginx/conf/sites-available/sso.maanas.co/login.lua;

echo 'You are logged in. Please navigate to the resource.';
}

location = /logout {
# MIME type determined by default_type:
default_type 'text/plain';

access_by_lua_file /opt/nginx/conf/sites-available/sso.maanas.co/logout.lua;

# Return Success in the end
echo 'OK';

}

## Form Location

location = /dologin {
rewrite ^.*$ http://sso.maanas.co/sso/index.html break;
#proxy_pass http://sso.maanas.co/sso/index.html;
#proxy_set_header Host 'sso.maanas.co';
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location = /401 {
rewrite ^.*$ http://sso.maanas.co/sso/unauthorized.html break;
#proxy_pass http://sso.maanas.co/sso/unauthorized.html;
#proxy_set_header Host 'sso.maanas.co';
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}


# Sample Endpoint
location = /apps/default {
# MIME type determined by default_type:
default_type 'text/plain';

# Add this to enable SSO on any location
# Specify the app which validate the access
set $app 'default';
access_by_lua_file /opt/nginx/conf/sites-available/sso.maanas.co/sso.lua;

# Normal Execution Continues
echo 'OK';
}


# This block will catch static file requests, such as images, css, js
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
# Some basic cache-control for static files to be sent to the browser
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}

# remove the robots line if you want to use wordpress' virtual robots.txt
location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }

# this prevents hidden files (beginning with a period) from being served
location ~ /\. { access_log off; log_not_found off; deny all; }

34 changes: 34 additions & 0 deletions nginx-conf/sso.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- Single Sign On Module in Lua
-- Check we got a request again a resource

-- Check we got session_token
if (ngx.var.cookie_session_token == nil or ngx.var.cookie_session_token == "") then
-- Track the endpoint for redirection later
ngx.header["Set-Cookie"] = "MNPLRedirectBack=http://"..ngx.var.host..ngx.var.uri..";path=/;domain=.maanas.co;Max-Age=120"
return ngx.redirect("http://sso.maanas.co/sso")
else
-- Sanity Check for session_token
if string.match(ngx.var.cookie_session_token,"%W") then
-- We got a poisioned cookie
ngx.exit(ngx.HTTP_BAD_REQUEST)
else
if (ngx.var.app == nil or ngx.var.app == "") then
-- We do not got an app match against the authrization
ngx.exit(ngx.HTTP_NOT_FOUND)
end
-- Sanity Check for app is not needed as it is internal request
local resp = ngx.location.capture("/sso/session?app="..ngx.var.app)
if resp.status == 200 then
_, _, no, uid, data = string.find(resp.body, [[%[%{"no":(%d+),"uid":(%d+),"data":"(%w*)"%}%]%s*]])
if tonumber(no) == 1 then
-- Found valid permission Update lastaccess time stamp and return
-- Update token timestamp in session
ngx.location.capture("/sso/session/update?token="..ngx.var.cookie_session_token)
return
else
ngx.header["Set-Cookie"] = "MNPLRedirectBack=http://"..ngx.var.host..ngx.var.uri..";path=/;domain=.maanas.co;Max-Age=120"
return ngx.redirect("/401")
end
end
end
end
Loading

0 comments on commit 6d62770

Please sign in to comment.