git.fiddlerwoaroof.com
Browse code

merge branch 'not-own-token'

Greg Wiley authored on 02/05/2017 23:43:18
Showing 17 changed files
... ...
@@ -3,9 +3,9 @@ CFLAGS += -fPIC -fno-stack-protector
3 3
 LDFLAGS = -lpam
4 4
 
5 5
 INTEGRATION_OBJS = sys_syslog.o sys_fstream.o sys_unistd.o sys_pwd.o sys_pam.o dual_control_integrate.o
6
-OBJS = dual_control.o request.o validator.o conversation.o user.o token.o logger.o
6
+OBJS = dual_control.o request.o validator.o conversation.o user.o token.o logger.o session.o
7 7
 TESTS = dual_control_test validator_test conversation_test request_test user_test token_test \
8
-		logger_test
8
+		logger_test session_test
9 9
 TESTOBJS = $(patsubst %,%.o,$(TESTS))
10 10
 SRCS := $(OBJS:.o=.cc) $(TESTOBJS:.o=.cc)
11 11
 
12 12
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+- look up requester user and fail if not found
2
+
... ...
@@ -82,7 +82,7 @@ private:
82 82
     pam_handle *expected_handle_;
83 83
     conversation_data conversation_data_;
84 84
     int get_response_;
85
-    pam_conv conv_;
85
+    mutable pam_conv conv_;
86 86
 public:
87 87
     fake_pam (pam_handle *expected_handle,
88 88
               const conversation_data &conversation_data)
... ...
@@ -91,7 +91,7 @@ public:
91 91
           get_response_ (PAM_SUCCESS)
92 92
     {}
93 93
     fake_pam (int get_response) : get_response_ (get_response) {}
94
-    int get_conv (pam_handle *handle, const pam_conv **out)
94
+    int get_conv (pam_handle *handle, const pam_conv **out) const
95 95
     {
96 96
         if (get_response_ != PAM_SUCCESS) {
97 97
             return get_response_;
... ...
@@ -101,7 +101,7 @@ public:
101 101
             throw std::string ("unexpected handle");
102 102
         }
103 103
 
104
-        conv_.appdata_ptr = reinterpret_cast<void *> (&conversation_data_);
104
+        conv_.appdata_ptr = (void *) (&conversation_data_);
105 105
         conv_.conv = fake_conv;
106 106
         *out = &conv_;
107 107
         return PAM_SUCCESS;
... ...
@@ -17,6 +17,7 @@
17 17
 #include "dual_control.h"
18 18
 #include "conversation.h"
19 19
 #include "validator.h"
20
+#include "session.h"
20 21
 #include "logger.h"
21 22
 
22 23
 int dual_control_ifc::authenticate (const pam_request &request)
... ...
@@ -37,6 +38,7 @@ private:
37 38
     conversation conversation_;
38 39
     validator validator_;
39 40
     logger logger_;
41
+    sessions sessions_;
40 42
 public:
41 43
     impl (const dual_control_configuration &configuration);
42 44
     int authenticate (const pam_request &request);
... ...
@@ -46,7 +48,8 @@ public:
46 48
 impl::impl (const dual_control_configuration &configuration) :
47 49
     conversation_ (configuration.conversation),
48 50
     validator_ (configuration.validator),
49
-    logger_ (configuration.logger) {}
51
+    logger_ (configuration.logger),
52
+    sessions_ (configuration.sessions) {}
50 53
 
51 54
 int impl::setcred (const pam_request &request)
52 55
 {
... ...
@@ -57,7 +60,10 @@ int impl::authenticate (const pam_request &request)
57 60
 {
58 61
     conversation_result input (conversation_.initiate (request));
59 62
 
60
-    int auth_result = validator_.validate (input.user_name,
63
+    sessions_.user_name (request);
64
+
65
+    auto requester_user_name = sessions_.user_name (request);
66
+    int auth_result = validator_.validate ("anyone", input.user_name,
61 67
                                            input.token) ? PAM_SUCCESS : PAM_AUTH_ERR;
62 68
 
63 69
     logger_.log (auth_result, input.user_name, input.token);
... ...
@@ -24,11 +24,13 @@
24 24
 #include "validator.h"
25 25
 #include "conversation.h"
26 26
 #include "logger.h"
27
+#include "session.h"
27 28
 
28 29
 struct dual_control_configuration {
29 30
     class validator validator;
30 31
     class conversation conversation;
31 32
     class logger logger;
33
+    class sessions sessions;
32 34
 };
33 35
 
34 36
 class dual_control_ifc
... ...
@@ -29,6 +29,7 @@
29 29
 #include "sys_fstream.h"
30 30
 #include "sys_pam.h"
31 31
 #include "sys_syslog.h"
32
+#include "session.h"
32 33
 
33 34
 namespace
34 35
 {
... ...
@@ -46,9 +47,11 @@ dual_control initialize()
46 47
     conversation conversation (conversation::create (pam));
47 48
     sys_syslog sys_syslog (sys_syslog::create());
48 49
     logger logger (logger::create (sys_syslog));
50
+    sessions sessions (sessions::create (pam));
49 51
     configuration.validator = validator;
50 52
     configuration.logger = logger;
51 53
     configuration.conversation = conversation;
54
+    configuration.sessions = sessions;
52 55
     return dual_control::create (configuration);
53 56
 }
54 57
 dual_control dc = initialize();
... ...
@@ -92,7 +92,8 @@ private:
92 92
 public:
93 93
     fake_validator (const std::string &user,
94 94
                     const std::string &token): user_ (user), token_ (token) {}
95
-    bool validate (const std::string &user, const std::string &token)
95
+    bool validate (const std::string &requester, const std::string &user,
96
+                   const std::string &token)
96 97
     {
97 98
         return user_ == user && token_ == token;
98 99
     }
99 100
new file mode 100644
... ...
@@ -0,0 +1,41 @@
1
+/* Copyright (C) CJ Affiliate
2
+ *
3
+ * You may use, distribute and modify this code under  the
4
+ * terms of the  GNU General Public License  version 2  or
5
+ * later.
6
+ *
7
+ * You should have received a copy of the license with this
8
+ * file. If not, you will find a copy in the "LICENSE" file
9
+ * at https://github.com/cjdev/dual-control.
10
+ */
11
+
12
+#include <memory>
13
+#include <string>
14
+
15
+#include "session.h"
16
+#include "sys_pam.h"
17
+#include "request.h"
18
+
19
+namespace
20
+{
21
+class impl : public sessions_ifc
22
+{
23
+private:
24
+    pam pam_;
25
+public:
26
+    impl (const pam &pam) : pam_ (pam) {}
27
+    std::string user_name (const pam_request &request)  const
28
+    {
29
+        const char *user_name;
30
+        pam_.get_user (request.handle(), &user_name);
31
+        return user_name;
32
+    }
33
+};
34
+
35
+}
36
+
37
+sessions sessions::create (const pam &pam)
38
+{
39
+    return sessions (std::make_shared<impl> (pam));
40
+}
41
+
0 42
new file mode 100644
... ...
@@ -0,0 +1,45 @@
1
+/* Copyright (C) CJ Affiliate
2
+ *
3
+ * You may use, distribute and modify this code under  the
4
+ * terms of the  GNU General Public License  version 2  or
5
+ * later.
6
+ *
7
+ * You should have received a copy of the license with this
8
+ * file. If not, you will find a copy in the "LICENSE" file
9
+ * at https://github.com/cjdev/dual-control.
10
+ */
11
+
12
+#ifndef _SESSION_H_
13
+#define _SESSION_H_
14
+
15
+#include <string>
16
+
17
+#include "request.h"
18
+#include "sys_pam.h"
19
+
20
+class sessions_ifc
21
+{
22
+public:
23
+    virtual ~sessions_ifc () {}
24
+    virtual std::string user_name (const pam_request &request)  const
25
+    {
26
+        return "";
27
+    }
28
+};
29
+
30
+class sessions
31
+{
32
+private:
33
+    std::shared_ptr<sessions_ifc> delegate_;
34
+public:
35
+    sessions (std::shared_ptr<sessions_ifc> delegate =
36
+                  std::make_shared<sessions_ifc>()) : delegate_ (delegate) {}
37
+    std::string user_name (const pam_request &request) const
38
+    {
39
+        return delegate_->user_name (request);
40
+    }
41
+    static sessions create (const pam &pam);
42
+};
43
+
44
+#endif
45
+
0 46
new file mode 100644
... ...
@@ -0,0 +1,60 @@
1
+/* Copyright (C) CJ Affiliate
2
+ *
3
+ * You may use, distribute and modify this code under  the
4
+ * terms of the  GNU General Public License  version 2  or
5
+ * later.
6
+ *
7
+ * You should have received a copy of the license with this
8
+ * file. If not, you will find a copy in the "LICENSE" file
9
+ * at https://github.com/cjdev/dual-control.
10
+ */
11
+
12
+#include <string>
13
+#include <memory>
14
+
15
+#include "session.h"
16
+#include "test_util.h"
17
+#include "sys_pam.h"
18
+#include "request.h"
19
+
20
+class fake_sys_pam : public pam_ifc
21
+{
22
+private:
23
+    std::string user_name_;
24
+public:
25
+    fake_sys_pam (std::string user_name) : user_name_ (user_name) {}
26
+    int get_user (pam_handle *handle, const char **out) const
27
+    {
28
+        *out = user_name_.c_str();
29
+        return PAM_SUCCESS;
30
+    }
31
+};
32
+
33
+int gets_user_from_pam()
34
+{
35
+    //given
36
+    std::string user_name ("user");
37
+    pam fake_sys_pam (std::make_shared<fake_sys_pam> (user_name));
38
+    sessions sessions (sessions::create (fake_sys_pam));
39
+    pam_request request (0, 0, 0, 0);
40
+
41
+    //when
42
+    std::string actual = sessions.user_name (request);
43
+
44
+    //
45
+    //then
46
+    check (actual == user_name, "returned wrong user name");
47
+    succeed();
48
+}
49
+
50
+int run_tests()
51
+{
52
+    test (gets_user_from_pam);
53
+    succeed();
54
+}
55
+
56
+int main (int argc, char *argv[])
57
+{
58
+    return !run_tests();
59
+}
60
+
... ...
@@ -21,10 +21,14 @@ namespace
21 21
 class impl : public pam_ifc
22 22
 {
23 23
 public:
24
-    int get_conv (pam_handle *handle, const pam_conv **out)
24
+    int get_conv (pam_handle *handle, const pam_conv **out) const
25 25
     {
26 26
         return ::pam_get_item (handle, PAM_CONV, (const void **)out);
27 27
     }
28
+    int get_user (pam_handle *handle, const char **out) const
29
+    {
30
+        return ::pam_get_item (handle, PAM_USER, (const void **)out);
31
+    }
28 32
 };
29 33
 }
30 34
 
... ...
@@ -19,7 +19,11 @@ class pam_ifc
19 19
 {
20 20
 public:
21 21
     virtual ~pam_ifc() {}
22
-    virtual int get_conv (pam_handle *handle, const pam_conv **out)
22
+    virtual int get_user (pam_handle *handle, const char **out) const
23
+    {
24
+        return PAM_SERVICE_ERR;
25
+    }
26
+    virtual int get_conv (pam_handle *handle, const pam_conv **out) const
23 27
     {
24 28
         return PAM_SERVICE_ERR;
25 29
     }
... ...
@@ -33,7 +37,11 @@ private:
33 37
 public:
34 38
     pam (const delegate &delegate) : delegate_ (delegate) {}
35 39
     pam() : pam (delegate (new pam_ifc)) {}
36
-    int get_conv (pam_handle *handle, const pam_conv **out)
40
+    int get_user (pam_handle *handle, const char **out) const
41
+    {
42
+        return delegate_->get_user (handle, out);
43
+    }
44
+    int get_conv (pam_handle *handle, const pam_conv **out) const
37 45
     {
38 46
         return delegate_->get_conv (handle, out);
39 47
     }
... ...
@@ -32,7 +32,6 @@
32 32
 
33 33
 #define test(NAME) \
34 34
     { \
35
-      __reset_vars(); \
36 35
       int result = NAME (); \
37 36
       if (!result) { \
38 37
           fprintf(stderr, "test failed: %s\n", #NAME); \
... ...
@@ -26,10 +26,19 @@ public:
26 26
           const user_token_supplier user_token_supplier) :
27 27
         directory_ (directory),
28 28
         user_token_supplier_ (user_token_supplier) {}
29
-    bool validate (const std::string &user_name,
29
+    bool validate (const std::string &requester_user_name,
30
+                   const std::string &authorizer_user_name,
30 31
                    const std::string &token)
31 32
     {
32
-        std::vector<user> found_user = directory_.find_user (user_name);
33
+        std::vector<user> found_user = directory_.find_user (authorizer_user_name);
34
+
35
+        if (requester_user_name.empty()) {
36
+            return false;
37
+        }
38
+
39
+        if (requester_user_name == authorizer_user_name) {
40
+            return false;
41
+        }
33 42
 
34 43
         if (found_user.empty()) {
35 44
             return false;
... ...
@@ -22,8 +22,9 @@ class validator_ifc
22 22
 {
23 23
 public:
24 24
     virtual ~validator_ifc() {}
25
-    virtual bool validate (const std::string &user_name,
26
-                           const std::string &token)
25
+    virtual bool validate (const std::string &requester_user_name,
26
+                           const std::string &authorizer_user_name,
27
+                           const std::string &authorizer_token)
27 28
     {
28 29
         return false;
29 30
     }
... ...
@@ -38,9 +39,12 @@ public:
38 39
         (delegate) {}
39 40
     validator() : validator (std::shared_ptr<validator_ifc>
40 41
                                  (new validator_ifc)) {}
41
-    bool validate (const std::string &user_name, const std::string &token)
42
+    bool validate (const std::string &requester_user_name,
43
+                   const std::string &authorizer_user_name,
44
+                   const std::string &authorizer_token)
42 45
     {
43
-        return delegate_->validate (user_name, token);
46
+        return delegate_->validate (requester_user_name, authorizer_user_name,
47
+                                    authorizer_token);
44 48
     }
45 49
     static validator create (const directory &directory,
46 50
                              const user_token_supplier &token_supplier);
... ...
@@ -70,7 +70,7 @@ bool validator_validates()
70 70
     validator validator = validator::create (directory, user_token_supplier);
71 71
 
72 72
     // when
73
-    bool actual = validator.validate (user_name, token);
73
+    bool actual = validator.validate ("requester", user_name, token);
74 74
 
75 75
     // then
76 76
     check (actual, "should be valid");
... ...
@@ -88,7 +88,7 @@ bool validator_fails_unknown_user()
88 88
     validator validator = validator::create (directory, user_token_supplier);
89 89
 
90 90
     // when
91
-    bool actual = validator.validate ("notuser", token);
91
+    bool actual = validator.validate ("requester", "notuser", token);
92 92
 
93 93
     // then
94 94
     check (!actual, "should not be valid");
... ...
@@ -106,13 +106,55 @@ bool validator_fails_incorrect_token()
106 106
     validator validator = validator::create (directory, user_token_supplier);
107 107
 
108 108
     // when
109
-    bool actual = validator.validate (user_name, "token");
109
+    bool actual = validator.validate ("requester", user_name, "token");
110 110
 
111 111
     // then
112 112
     check (!actual, "should not be valid");
113 113
     succeed();
114 114
 }
115 115
 
116
+bool validator_fails_with_own_token()
117
+{
118
+    // given
119
+    std::string requester_user_name ("requester");
120
+    std::string authorizer_user_name (requester_user_name);
121
+    std::string authorizer_token ("token");
122
+    directory directory (share (new fake_directory (authorizer_user_name)));
123
+    user_token_supplier user_token_supplier (share (new
124
+            fake_user_token_supplier (authorizer_token)));
125
+    validator validator = validator::create (directory, user_token_supplier);
126
+
127
+    // when
128
+    bool actual = validator.validate (requester_user_name, authorizer_user_name,
129
+                                      authorizer_token);
130
+
131
+    // then
132
+    check (!actual, "should not be valid");
133
+    succeed();
134
+
135
+}
136
+
137
+bool validator_fails_with_unknown_requester()
138
+{
139
+    // given
140
+    std::string requester_user_name ("");
141
+    std::string authorizer_user_name ("authorizer");
142
+    std::string authorizer_token ("token");
143
+    directory directory (share (new fake_directory (authorizer_user_name)));
144
+    user_token_supplier user_token_supplier (share (new
145
+            fake_user_token_supplier (authorizer_token)));
146
+    validator validator = validator::create (directory, user_token_supplier);
147
+
148
+    // when
149
+    bool actual = validator.validate (requester_user_name, authorizer_user_name,
150
+                                      authorizer_token);
151
+
152
+    // then
153
+    check (!actual, "should not be valid");
154
+    succeed();
155
+
156
+}
157
+
116 158
 RESET_VARS_START
117 159
 RESET_VARS_END
118 160
 
... ...
@@ -121,6 +163,8 @@ bool run_tests()
121 163
     test (validator_validates);
122 164
     test (validator_fails_unknown_user);
123 165
     test (validator_fails_incorrect_token);
166
+    test (validator_fails_with_own_token);
167
+    test (validator_fails_with_unknown_requester);
124 168
     succeed();
125 169
 }
126 170
 
127 171
new file mode 100755
... ...
@@ -0,0 +1,8 @@
1
+#!/bin/bash
2
+
3
+if ! which fswatch > /dev/null; then
4
+    echo 'fswatch is required https://github.com/emcrisostomo/fswatch'
5
+    exit 1
6
+fi
7
+fswatch -E --exclude '.' --include='\.(cc|h)$' -o $(dirname $0) | xargs -n1 -I{} make test
8
+