Browse code
merge branch 'not-own-token'
Showing 17 changed files
- Makefile.in
- TODO.md
- conversation_test.cc
- dual_control.cc
- dual_control.h
- dual_control_integrate.cc
- dual_control_test.cc
- session.cc
- session.h
- session_test.cc
- sys_pam.cc
- sys_pam.h
- test_util.h
- validator.cc
- validator.h
- validator_test.cc
- watch.sh
... | ... |
@@ -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 |
|
... | ... |
@@ -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 |
} |
... | ... |
@@ -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 |
|