dd006b418c7c161bd46b061c7f3e9345fbf34c28
[gssweb.git] / json_gssapi / test / GSSCreateSecContextTest.cpp
1 /*
2  * Copyright (c) 2014 <copyright holder> <email>
3  * 
4  * For license details, see the LICENSE file in the root of this project.
5  * 
6  */
7
8
9 #include "GSSCreateSecContextTest.h"
10 #include "GSSInitSecContext.h"
11 #include "command_mocks/InitSecContextMock.h"
12 #include <iostream>
13 #include <string.h>
14 #include <exception>
15 #include "util_json.h"
16 #include <cache/GSSContextCache.h>
17 #include <cache/GSSNameCache.h>
18 #include <datamodel/GSSContext.h>
19 #include <utils/base64.h>
20
21 // Registers the fixture into the 'registry'
22 CPPUNIT_TEST_SUITE_REGISTRATION( GSSCreateSecContextTest );
23
24 using std::cout;
25
26 static OM_uint32 KRB5_CALLCONV
27 mock_init_sec(
28     OM_uint32             *minor_status,
29     gss_cred_id_t          claimant_cred_handle,
30     gss_ctx_id_t          *context_handle,
31     gss_name_t             target_name,
32     gss_OID                mech_type,
33     OM_uint32              req_flags,
34     OM_uint32              time_req,
35     gss_channel_bindings_t input_chan_bindings,
36     gss_buffer_t           input_token,
37     gss_OID               *actual_mech_type,
38     gss_buffer_t           output_token,
39     OM_uint32             *ret_flags,
40     OM_uint32             *time_rec)
41 {
42   gss_ctx_id_t tmpContext;
43   
44   InitSecContextMock::visited = true;
45   
46   /* Copy in the input to this function */
47   InitSecContextMock::claimant_cred_handle = claimant_cred_handle;
48   InitSecContextMock::target_name = target_name;
49   InitSecContextMock::mech_type = mech_type;
50   InitSecContextMock::req_flags = req_flags;
51   InitSecContextMock::time_req = time_req;
52   InitSecContextMock::input_chan_bindings = input_chan_bindings;
53   InitSecContextMock::input_token.length = input_token->length;
54   InitSecContextMock::input_token.value = input_token->value;
55   
56   
57   /* Copy out the output from this function */
58   *minor_status = InitSecContextMock::minor_status;
59   *actual_mech_type = InitSecContextMock::actual_mech_type;
60   output_token->length = InitSecContextMock::output_token.length;
61   output_token->value = InitSecContextMock::output_token.value;
62   *ret_flags = InitSecContextMock::ret_flags;
63   *time_rec = InitSecContextMock::time_rec;
64   
65   /* Handle the one that's I/O */
66   tmpContext = *context_handle;
67   *context_handle = InitSecContextMock::context_handle;
68   InitSecContextMock::context_handle = tmpContext;
69
70   return InitSecContextMock::retVal;
71 }
72
73
74 void
75 GSSCreateSecContextTest::setUp()
76 {
77   InitSecContextMock::reset();
78 }
79
80 void
81 GSSCreateSecContextTest::tearDown()
82 {
83 }
84
85 void
86 GSSCreateSecContextTest::testConstructor()
87 {
88   GSSInitSecContext cmd = GSSInitSecContext();
89   void *cmdFn;
90   void *GSSFn;
91   
92   cmdFn = cmd.getGSSFunction();
93   GSSFn = (void *)&gss_init_sec_context;
94   CPPUNIT_ASSERT_MESSAGE(
95     "The default constructor for GSSCreateSecContextCommand should assign the function gss_init_sec_context", 
96     cmdFn == GSSFn);
97   
98   // Check that we defaut to the moonshot OID
99   CPPUNIT_ASSERT_EQUAL_MESSAGE(
100     "The mech_type default value is unexpected.",
101     std::string("{ 1 3 6 1 5 5 15 1 1 18 }"),
102     cmd.getMechType().toString()
103   );
104 }
105
106 /* JSON Input:
107  * { 
108  *   "method": "gss_create_sec_context",
109  *   "arguments": 
110  *   {
111  *     "req_flags": "1",
112  *     "time_req": "2",
113  *     "mech_type": "{ 1 2 840 113554 1 2 1 4 }",
114  *     "target_name": "me@my.sha/DOW"
115  *   }
116  * }
117  */
118 void GSSCreateSecContextTest::testConstructorWithJSONObject()
119 {
120   OM_uint32 major, minor;
121   gss_name_t src;
122   GSSName source;
123   char *source_name = (char *)"HTTP@localhost\0";
124   
125   
126   major = gss_import_name(&minor, GSSBuffer(source_name).toGss(), GSS_C_NT_HOSTBASED_SERVICE, &src);
127   if (GSS_ERROR(major))
128   {
129     OM_uint32 min, context;
130     gss_buffer_desc buf;
131     
132     std::cout << "Error in importing name." << std::endl;
133     gss_display_status(&min, major, GSS_C_GSS_CODE, GSS_C_NT_HOSTBASED_SERVICE, &context, &buf);
134     std::cout << "  message: " << (char *)buf.value << std::endl;
135   }
136   CPPUNIT_ASSERT_MESSAGE(
137     "Could not generate a name to test GSSCreateSecContext JSON parsing.",
138     !GSS_ERROR(major)
139   );
140   source.setValue(src);
141   std::string key = GSSNameCache::instance()->store(source);
142
143   std::string input = "{\"req_flags\": \"1\", \
144     \"time_req\": \"2\", \
145     \"mech_type\": \"{ 1 2 840 113554 1 2 1 4 }\", \
146     \"target_name\": \"";
147   input = input + key + "\"}";
148
149   json_error_t jsonErr;
150   const char *in = input.c_str();
151   JSONObject json = JSONObject::load(in, 0, &jsonErr);
152   
153   GSSInitSecContext cmd = GSSInitSecContext(
154     &json, 
155     (void *)&mock_init_sec
156   );
157
158   const char *from_cmd = cmd.getTargetDisplayName();
159   
160   CPPUNIT_ASSERT_MESSAGE(
161     "The object does not have a target name.",
162     ( strcmp(source_name, from_cmd) == 0 )
163   );
164   
165   CPPUNIT_ASSERT_EQUAL_MESSAGE(
166     "The context_handle values differ.",
167     json["context_handle"].integer(),
168     (json_int_t)cmd.getContextHandle()
169   );
170   
171   CPPUNIT_ASSERT_EQUAL_MESSAGE(
172     "The mech_type values differ.",
173     std::string(json["mech_type"].string()), 
174     cmd.getMechType().toString()
175   );
176   
177   CPPUNIT_ASSERT_EQUAL_MESSAGE(
178     "The req_flags differ.",
179     (int)json["req_flags"].integer(),
180     (int)cmd.getReqFlags()
181   );
182   
183   CPPUNIT_ASSERT_EQUAL_MESSAGE(
184     "The req_flags differ.",
185     (int)json["time_req"].integer(),
186     (int)cmd.getTimeReq()
187   );
188   
189 }
190
191 void
192 GSSCreateSecContextTest::testEmptyCall()
193 {
194   gss_ctx_id_t expectedResult, expectedArgument;
195   
196   GSSInitSecContext cmd ((void *)&mock_init_sec);
197   
198   /* Set expectations on what the GSS function will be called with */
199   cmd.time_req = rand() % 1024;
200   cmd.req_flags = rand() % 1024;
201   cmd.target_name = NULL;
202   cmd.context_handle = expectedArgument = (gss_ctx_id_t)(long)rand();
203   
204   
205   
206   /* Set expectations on what the GSS function will produce */
207   InitSecContextMock::retVal = rand() % 1024;
208   InitSecContextMock::minor_status = rand() % 1024;
209   InitSecContextMock::context_handle = expectedResult = (gss_ctx_id_t)(long)rand();
210   InitSecContextMock::actual_mech_type = NULL;
211   InitSecContextMock::output_token.value = (void *)"http@project-moonshot.org/PROJECT-MOONSHOT.ORG\0";
212   InitSecContextMock::output_token.length = strlen((char *)InitSecContextMock::output_token.value);
213   InitSecContextMock::ret_flags = rand() % 1024;
214   InitSecContextMock::time_req = rand() % 1024;
215   
216   cmd.execute();
217   
218   /* Check that init_sec_context's inputs are sent correctly */
219   CPPUNIT_ASSERT_MESSAGE(
220     "The GSS function was not invoked!",
221     InitSecContextMock::visited
222   );
223   CPPUNIT_ASSERT_EQUAL_MESSAGE(
224     "The time_req field was not used in the call to init_sec_context",
225     cmd.time_req,
226     InitSecContextMock::time_req
227   );
228   CPPUNIT_ASSERT_EQUAL_MESSAGE(
229     "The req_flags field was not used in the call to init_sec_context",
230     cmd.req_flags,
231     InitSecContextMock::req_flags
232   );
233   CPPUNIT_ASSERT_EQUAL_MESSAGE(
234     "The mech_type field was not used in the call to init_sec_context",
235     cmd.getMechType().toGss(),
236     InitSecContextMock::mech_type
237   );
238   CPPUNIT_ASSERT_EQUAL_MESSAGE(
239     "The target_name field was not used in the call to init_sec_context",
240     cmd.target_name,
241     InitSecContextMock::target_name
242   );
243   
244   
245   /* Check that init_sec_context's outputs are captured correctly */
246   CPPUNIT_ASSERT_EQUAL_MESSAGE(
247     "Return value was not copied back to the command.",
248     InitSecContextMock::retVal,
249     cmd.retVal
250   );
251   CPPUNIT_ASSERT_EQUAL_MESSAGE(
252     "Status was not copied back to the command.",
253     InitSecContextMock::minor_status,
254     cmd.minor_status
255   );
256   CPPUNIT_ASSERT_EQUAL_MESSAGE(
257     "context_handle was not copied back to the command.",
258     expectedResult,
259     cmd.context_handle
260   );
261   CPPUNIT_ASSERT_EQUAL_MESSAGE(
262     "context_handle was not copied back to the command.",
263     expectedArgument,
264     InitSecContextMock::context_handle
265   );
266   CPPUNIT_ASSERT_EQUAL_MESSAGE(
267     "actual_mech_type was not copied back to the command.",
268     InitSecContextMock::actual_mech_type,
269     cmd.getActualMechType().toGss()
270   );
271   CPPUNIT_ASSERT_EQUAL_MESSAGE(
272     "output_token was not copied back to the command.",
273     InitSecContextMock::output_token.value,
274     cmd.output_token.value
275   );
276   CPPUNIT_ASSERT_EQUAL_MESSAGE(
277     "ret_flags was not copied back to the command.",
278     InitSecContextMock::ret_flags,
279     cmd.ret_flags
280   );
281   CPPUNIT_ASSERT_EQUAL_MESSAGE(
282     "time_rec was not copied back to the command.",
283     InitSecContextMock::time_rec,
284     cmd.time_rec
285   );
286   
287   // Set this to no context, or cleanup attempts to free the not-a-real-pointer.
288   InitSecContextMock::context_handle = GSS_C_NO_CONTEXT;
289   
290 }
291
292 /* Expected JSON output:
293  * 
294  * {
295  *   "command": "gss_init_sec_context", 
296  *   "return_values": 
297  *   {
298  *     "context_handle": "base64_encoded_string", 
299  *     "major_status": ##, 
300  *     "output_token": "http@project-moonshot.org/PROJECT-MOONSHOT.ORG", 
301  *     "actual_mech_type": "{ 1 3 6 1 5 5 13 4 }", 
302  *     "minor_status": ##, 
303  *     ret_flags": ##, 
304  *     "time_rec": ##
305  *   }
306  * }
307  * 
308  */
309 void GSSCreateSecContextTest::testJSONMarshal()
310 {
311   /* Variables */
312   GSSInitSecContext cmd ((void *)&mock_init_sec);
313   JSONObject *result;
314   GSSContextCache *cache = GSSContextCache::instance();
315   GSSContext context;
316   gss_ctx_id_t expectedResult;
317   
318   /* Error checking */
319   
320   /* Setup */
321   // Set expectations on what the GSS function will produce
322   InitSecContextMock::retVal = GSS_S_CONTINUE_NEEDED;
323   InitSecContextMock::minor_status = 0;
324   InitSecContextMock::context_handle = expectedResult = (gss_ctx_id_t)(long)rand();
325   InitSecContextMock::actual_mech_type = (gss_OID)GSS_C_MA_MECH_NEGO;
326   InitSecContextMock::output_token.value = (void *)"http@project-moonshot.org/PROJECT-MOONSHOT.ORG\0";
327   InitSecContextMock::output_token.length = strlen((char *)InitSecContextMock::output_token.value);
328   InitSecContextMock::ret_flags = GSS_C_MUTUAL_FLAG | 
329       GSS_C_REPLAY_FLAG | 
330       GSS_C_SEQUENCE_FLAG | 
331       GSS_C_CONF_FLAG | 
332       GSS_C_INTEG_FLAG | 
333       GSS_C_ANON_FLAG | 
334       GSS_C_PROT_READY_FLAG;
335   InitSecContextMock::time_req = GSS_C_INDEFINITE;
336   
337   /* Main */
338   cmd.execute();
339   result = cmd.toJSON();
340 /*  
341   std::cout << "create sec context json: " << result->dump() << "\n";*/
342   
343   CPPUNIT_ASSERT_EQUAL_MESSAGE(
344     "The return value was reported incorrectly",
345     (int)InitSecContextMock::retVal,
346     (int)( (*result)["major_status"].integer() )
347   );
348   
349   CPPUNIT_ASSERT_EQUAL_MESSAGE(
350     "The minor_status value was reported incorrectly",
351     (int)InitSecContextMock::minor_status,
352     (int)( (*result)["minor_status"].integer() )
353   );
354   
355   CPPUNIT_ASSERT_MESSAGE(
356     "The actual_mech_type value was reported incorrectly",
357     ( strcmp("{ 1 3 6 1 5 5 13 4 }", 
358              (*result)["actual_mech_type"].string() ) == 0 )
359   );
360
361   
362   
363   unsigned long len;
364   std::string str = (*result)["output_token"].string();
365   unsigned char *decoded = base64_decode(str, &len);
366   CPPUNIT_ASSERT_MESSAGE(
367     "The output_token value was reported incorrectly",
368     ( strcmp((const char *)(InitSecContextMock::output_token.value), 
369              (const char *)decoded ) == 0 )
370   );
371   
372   CPPUNIT_ASSERT_EQUAL_MESSAGE(
373     "The minor_status value was reported incorrectly",
374     (int)InitSecContextMock::ret_flags,
375     (int)( (*result)["ret_flags"].integer() )
376   );
377   
378   CPPUNIT_ASSERT_EQUAL_MESSAGE(
379     "The minor_status value was reported incorrectly",
380     (int)InitSecContextMock::time_rec,
381     (int)( (*result)["time_rec"].integer() )
382   );
383   
384   context = cache->retrieve( (*result)["context_handle"].string() );
385   
386   CPPUNIT_ASSERT_EQUAL_MESSAGE(
387     "The returned context was reported incorrectly",
388     (long)expectedResult,
389     (long)context.getContext()
390   );
391   
392   /* Cleanup */
393   /* Return */
394 }
395
396