Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
6572c1c6
Commit
6572c1c6
authored
8 years ago
by
Deomid Ryabkov
Committed by
Cesanta Bot
8 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a cookie auth and session management example
PUBLISHED_FROM=243437cf7d48b04aef3896bc4c5d4010975299a4
parent
7b48859f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
299 additions
and
0 deletions
+299
-0
Makefile
examples/cookie_auth/Makefile
+2
-0
cookie_auth.c
examples/cookie_auth/cookie_auth.c
+254
-0
login.html
examples/cookie_auth/login.html
+43
-0
No files found.
examples/cookie_auth/Makefile
0 → 100644
View file @
6572c1c6
PROG
=
cookie_auth
include
../examples.mk
This diff is collapsed.
Click to expand it.
examples/cookie_auth/cookie_auth.c
0 → 100644
View file @
6572c1c6
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*
* This example demonstrates how to implement cookie authentication
* and session management using Mongoose.
*/
#include <inttypes.h>
#include <stdlib.h>
#include "mongoose.h"
static
const
char
*
s_http_port
=
"8000"
;
static
struct
mg_serve_http_opts
s_http_server_opts
;
/* This is the name of the cookie carrying the session ID. */
#define SESSION_COOKIE_NAME "mgs"
/* In our example sessions are destroyed after 30 seconds of inactivity. */
#define SESSION_TTL 30.0
#define SESSION_CHECK_INTERVAL 5.0
/* Session information structure. */
struct
session
{
/* Session ID. Must be unique and hard to guess. */
uint64_t
id
;
/*
* Time when the session was created and time of last activity.
* Used to clean up stale sessions.
*/
double
created
;
double
last_used
;
/* Time when the session was last active. */
/* User name this session is associated with. */
char
*
user
;
/* Some state associated with user's session. */
int
lucky_number
;
};
/*
* This example uses a simple in-memory storage for just 10 sessions.
* A real-world implementation would use persistent storage of some sort.
*/
#define NUM_SESSIONS 10
struct
session
s_sessions
[
NUM_SESSIONS
];
/*
* Password check function.
* In our example all users have password "password".
*/
static
int
check_pass
(
const
char
*
user
,
const
char
*
pass
)
{
(
void
)
user
;
return
(
strcmp
(
pass
,
"password"
)
==
0
);
}
/*
* Parses the session cookie and returns a pointer to the session struct
* or NULL if not found.
*/
static
struct
session
*
get_session
(
struct
http_message
*
hm
)
{
struct
mg_str
*
cookie_header
=
mg_get_http_header
(
hm
,
"cookie"
);
if
(
cookie_header
==
NULL
)
return
NULL
;
char
ssid
[
21
];
if
(
!
mg_http_parse_header
(
cookie_header
,
SESSION_COOKIE_NAME
,
ssid
,
sizeof
(
ssid
)))
{
return
NULL
;
}
uint64_t
sid
=
strtoull
(
ssid
,
NULL
,
16
);
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
if
(
s_sessions
[
i
].
id
==
sid
)
{
s_sessions
[
i
].
last_used
=
mg_time
();
return
&
s_sessions
[
i
];
}
}
return
NULL
;
}
/*
* Destroys the session state.
*/
static
void
destroy_session
(
struct
session
*
s
)
{
free
(
s
->
user
);
memset
(
s
,
0
,
sizeof
(
*
s
));
}
/*
* Creates a new session for the user.
*/
static
struct
session
*
create_session
(
const
char
*
user
,
const
struct
http_message
*
hm
)
{
/* Find first available slot or use the oldest one. */
struct
session
*
s
=
NULL
;
struct
session
*
oldest_s
=
s_sessions
;
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
if
(
s_sessions
[
i
].
id
==
0
)
{
s
=
&
s_sessions
[
i
];
break
;
}
if
(
s_sessions
[
i
].
last_used
<
oldest_s
->
last_used
)
{
oldest_s
=
&
s_sessions
[
i
];
}
}
if
(
s
==
NULL
)
{
destroy_session
(
oldest_s
);
printf
(
"Evicted %"
INT64_X_FMT
"/%s
\n
"
,
oldest_s
->
id
,
oldest_s
->
user
);
s
=
oldest_s
;
}
/* Initialize new session. */
s
->
created
=
s
->
last_used
=
mg_time
();
s
->
user
=
strdup
(
user
);
s
->
lucky_number
=
rand
();
/* Create an ID by putting various volatiles into a pot and stirring. */
cs_sha1_ctx
ctx
;
cs_sha1_init
(
&
ctx
);
cs_sha1_update
(
&
ctx
,
(
const
unsigned
char
*
)
hm
->
message
.
p
,
hm
->
message
.
len
);
cs_sha1_update
(
&
ctx
,
(
const
unsigned
char
*
)
s
,
sizeof
(
*
s
));
unsigned
char
digest
[
20
];
cs_sha1_final
(
digest
,
&
ctx
);
s
->
id
=
*
((
uint64_t
*
)
digest
);
return
s
;
}
static
void
set_session_cookie
(
struct
mg_connection
*
nc
,
const
struct
session
*
s
)
{
mg_printf
(
nc
,
"Set-Cookie: %s=%"
INT64_X_FMT
"; path=/
\r\n
"
,
SESSION_COOKIE_NAME
,
s
->
id
);
}
/*
* If requested via GET, serves the login page.
* If requested via POST (form submission), checks password and logs user in.
*/
static
void
login_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
if
(
mg_vcmp
(
&
hm
->
method
,
"POST"
)
!=
0
)
{
/* Serve login.html */
mg_serve_http
(
nc
,
(
struct
http_message
*
)
p
,
s_http_server_opts
);
}
else
{
/* Perform password check. */
char
user
[
50
],
pass
[
50
];
int
ul
=
mg_get_http_var
(
&
hm
->
body
,
"user"
,
user
,
sizeof
(
user
));
int
pl
=
mg_get_http_var
(
&
hm
->
body
,
"pass"
,
pass
,
sizeof
(
pass
));
if
(
ul
>
0
&&
pl
>
0
)
{
if
(
check_pass
(
user
,
pass
))
{
struct
session
*
s
=
create_session
(
user
,
hm
);
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
);
set_session_cookie
(
nc
,
s
);
mg_printf
(
nc
,
"Location: /
\r\n
"
);
mg_printf
(
nc
,
"
\r\n
Hello, %s!
\r\n
"
,
s
->
user
);
fprintf
(
stderr
,
"%s logged in, sid %"
INT64_X_FMT
"
\n
"
,
s
->
user
,
s
->
id
);
}
else
{
mg_printf
(
nc
,
"HTTP/1.0 403 Unauthorized
\r\n\r\n
Wrong password.
\r\n
"
);
}
}
else
{
mg_printf
(
nc
,
"HTTP/1.0 400 Bad Request
\r\n\r\n
user, pass required.
\r\n
"
);
}
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
(
void
)
ev
;
}
/*
* Logs the user out.
* Removes cookie and any associated session state.
*/
static
void
logout_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
"Set-Cookie: %s=
\r\n
"
"Location: /
\r\n
"
"
\r\n
"
"Logged out"
,
SESSION_COOKIE_NAME
);
struct
session
*
s
=
get_session
(
hm
);
if
(
s
!=
NULL
)
{
fprintf
(
stderr
,
"%s logged out, session %"
INT64_X_FMT
" destroyed
\n
"
,
s
->
user
,
s
->
id
);
destroy_session
(
s
);
}
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
(
void
)
ev
;
}
/* Cleans up sessions that have been idle for too long. */
void
check_sessions
()
{
double
threshold
=
mg_time
()
-
SESSION_TTL
;
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
struct
session
*
s
=
&
s_sessions
[
i
];
if
(
s
->
id
!=
0
&&
s
->
last_used
<
threshold
)
{
fprintf
(
stderr
,
"Session %"
INT64_X_FMT
" (%s) closed due to idleness.
\n
"
,
s
->
id
,
s
->
user
);
destroy_session
(
s
);
}
}
}
/* Main event handler. */
static
void
ev_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
/* Perform session maintenance. */
if
(
ev
==
MG_EV_TIMER
)
{
check_sessions
();
mg_set_timer
(
nc
,
mg_time
()
+
SESSION_CHECK_INTERVAL
);
return
;
}
if
(
ev
!=
MG_EV_HTTP_REQUEST
)
return
;
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
struct
session
*
s
=
get_session
(
hm
);
/* Ask the user to log in if they did not present a valid cookie. */
if
(
s
==
NULL
)
{
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
"Location: /login.html
\r\n
"
"
\r\n
"
"Please log in"
);
return
;
}
/* Application logic that uses session data goes here. */
fprintf
(
stderr
,
"%s (sid %"
INT64_X_FMT
") requested %.*s
\n
"
,
s
->
user
,
s
->
id
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
mg_printf
(
nc
,
"HTTP/1.0 200 Ok
\r\n
"
"COntent-Type: text/html
\r\n
"
"
\r\n
"
"<h1>Hello, %s!</h1>
\r\n
"
"<p>Your lucky number is %d.</p>
\r\n
"
"<p><a href=/logout>Log out</a>"
,
s
->
user
,
s
->
lucky_number
);
}
int
main
(
void
)
{
struct
mg_mgr
mgr
;
struct
mg_connection
*
nc
;
srand
(
mg_time
());
mg_mgr_init
(
&
mgr
,
NULL
);
nc
=
mg_bind
(
&
mgr
,
s_http_port
,
ev_handler
);
mg_set_protocol_http_websocket
(
nc
);
s_http_server_opts
.
document_root
=
"."
;
mg_register_http_endpoint
(
nc
,
"/login.html"
,
login_handler
);
mg_register_http_endpoint
(
nc
,
"/logout"
,
logout_handler
);
mg_set_timer
(
nc
,
mg_time
()
+
SESSION_CHECK_INTERVAL
);
printf
(
"Starting web server on port %s
\n
"
,
s_http_port
);
for
(;;)
{
mg_mgr_poll
(
&
mgr
,
1000
);
}
mg_mgr_free
(
&
mgr
);
return
0
;
}
This diff is collapsed.
Click to expand it.
examples/cookie_auth/login.html
0 → 100644
View file @
6572c1c6
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
/>
<title>
Please log in
</title>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
/>
<style
type=
"text/css"
>
*
{
outline
:
none
;
}
body
{
background-color
:
#789
;
margin
:
0
;
padding
:
0
;
font
:
16px
/
1.4
Helvetica
,
Arial
,
sans-serif
;
font
:
16px
/
1.4
Helvetica
,
Arial
,
sans-serif
;
}
div
.content
{
width
:
800px
;
margin
:
2em
auto
;
padding
:
20px
50px
;
background-color
:
#fff
;
border-radius
:
1em
;
}
label
{
display
:
inline-block
;
min-width
:
7em
;
}
input
{
border
:
1px
solid
#ccc
;
padding
:
0.2em
;
}
a
:link
,
a
:visited
{
color
:
#69c
;
text-decoration
:
none
;
}
@media
(
max-width
:
700px
)
{
body
{
background-color
:
#fff
;
}
div
.content
{
width
:
auto
;
margin
:
0
auto
;
padding
:
1em
;
}
}
</style>
</head>
<body>
<div
class=
"content"
>
<h1>
Please log in
</h1>
<form
method=
"POST"
>
<div>
<label>
Username:
</label>
<input
type=
"text"
name=
"user"
/>
</div>
<div>
<label>
Password:
</label>
<input
type=
"password"
name=
"pass"
/>
</div>
<div>
<input
type=
"submit"
value=
"Log in"
>
</div>
</form>
</div>
</body>
</html>
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment