1 module app;
2 
3 import vibe.core.core;
4 import vibe.core.log;
5 import vibe.http.auth.basic_auth;
6 import vibe.http.client;
7 import vibe.http.router;
8 import vibe.http.server;
9 import vibe.web.auth;
10 import vibe.web.web;
11 
12 import std.algorithm : among;
13 import std.datetime;
14 import std.format : format;
15 
16 
17 shared static this()
18 {
19 	auto settings = new HTTPServerSettings;
20 	settings.port = 0;
21 	settings.bindAddresses = ["127.0.0.1"];
22 	auto router = new URLRouter;
23 	router.registerWebInterface(new Service);
24 	immutable serverAddr = listenHTTP(settings, router).bindAddresses[0];
25 
26     runTask({
27         scope (exit) exitEventLoop();
28 
29         void test(string url, string user, HTTPStatus expected)
30         nothrow {
31             try {
32                 requestHTTP("http://" ~ serverAddr.toString ~ url, (scope req) {
33                     if (user !is null) req.addBasicAuth(user, "secret");
34                 }, (scope res) {
35                     res.dropBody();
36                     assert(res.statusCode == expected, format("Unexpected status code for GET %s (%s): %s", url, user, res.statusCode));
37                 });
38             } catch (Exception e) {
39                 assert(false, e.msg);
40             }
41         }
42 
43         test("/public", null, HTTPStatus.ok);
44         test("/any", null, HTTPStatus.unauthorized);
45         test("/any", "stacy", HTTPStatus.ok);
46         test("/any_a", null, HTTPStatus.unauthorized);
47         test("/any_a", "stacy", HTTPStatus.ok);
48         test("/admin", null, HTTPStatus.unauthorized);
49         test("/admin", "admin", HTTPStatus.ok);
50         test("/admin", "peter", HTTPStatus.forbidden);
51         test("/admin", "stacy", HTTPStatus.forbidden);
52         test("/admin_a", null, HTTPStatus.unauthorized);
53         test("/admin_a", "admin", HTTPStatus.ok);
54         test("/admin_a", "peter", HTTPStatus.forbidden);
55         test("/admin_a", "stacy", HTTPStatus.forbidden);
56         test("/member", "admin", HTTPStatus.forbidden);
57         test("/member", "peter", HTTPStatus.ok);
58         test("/member", "stacy", HTTPStatus.forbidden);
59         test("/admin_member", "peter", HTTPStatus.ok);
60         test("/admin_member", "admin", HTTPStatus.ok);
61         test("/admin_member", "stacy", HTTPStatus.forbidden);
62         logInfo("All auth tests successful.");
63     });
64 }
65 
66 struct Auth {
67     string username;
68 
69     bool isAdmin() { return username == "admin"; }
70     bool isMember() { return username == "peter"; }
71 }
72 
73 @requiresAuth
74 class Service {
75     @noAuth void getPublic(HTTPServerResponse res) { res.writeBody("success"); }
76     @anyAuth void getAny(HTTPServerResponse res) { res.writeBody("success"); }
77     @anyAuth void getAnyA(HTTPServerResponse res, Auth auth) { assert(auth.username.among("admin", "peter", "stacy")); res.writeBody("success"); }
78     @auth(Role.admin) void getAdmin(HTTPServerResponse res) { res.writeBody("success"); }
79     @auth(Role.admin) void getAdminA(HTTPServerResponse res, Auth auth) { assert(auth.username == "admin"); res.writeBody("success"); }
80     @auth(Role.member) void getMember(HTTPServerResponse res) { res.writeBody("success"); }
81     @auth(Role.admin | Role.member) void getAdminMember(HTTPServerResponse res) { res.writeBody("success"); }
82 
83     @noRoute Auth authenticate(HTTPServerRequest req, HTTPServerResponse res)
84     {
85         Auth ret;
86         ret.username = performBasicAuth(req, res, "test", (user, pw) { return pw == "secret"; });
87         return ret;
88     }
89 }