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 }