Add copyright comment headers to appropriate files
[gssweb.git] / json_gssapi / test / GSSCreateSecContextTest.cpp
1 /*
2  * Copyright (c) 2014, 2015 JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35
36 #include "GSSCreateSecContextTest.h"
37 #include "GSSInitSecContext.h"
38 #include "command_mocks/InitSecContextMock.h"
39 #include <iostream>
40 #include <string.h>
41 #include <exception>
42 #include "utils/util_json.h"
43 #include <cache/GSSContextCache.h>
44 #include <cache/GSSNameCache.h>
45 #include <datamodel/GSSContext.h>
46 #include <utils/util_base64.h>
47
48 // Registers the fixture into the 'registry'
49 CPPUNIT_TEST_SUITE_REGISTRATION( GSSCreateSecContextTest );
50
51 using std::cout;
52
53 static OM_uint32 KRB5_CALLCONV
54 mock_init_sec(
55     OM_uint32             *minor_status,
56     gss_cred_id_t          claimant_cred_handle,
57     gss_ctx_id_t          *context_handle,
58     gss_name_t             target_name,
59     gss_OID                mech_type,
60     OM_uint32              req_flags,
61     OM_uint32              time_req,
62     gss_channel_bindings_t input_chan_bindings,
63     gss_buffer_t           input_token,
64     gss_OID               *actual_mech_type,
65     gss_buffer_t           output_token,
66     OM_uint32             *ret_flags,
67     OM_uint32             *time_rec)
68 {
69   gss_ctx_id_t tmpContext;
70   
71   InitSecContextMock::visited = true;
72   
73   /* Copy in the input to this function */
74   InitSecContextMock::claimant_cred_handle = claimant_cred_handle;
75   InitSecContextMock::target_name = target_name;
76   InitSecContextMock::mech_type = mech_type;
77   InitSecContextMock::req_flags = req_flags;
78   InitSecContextMock::time_req = time_req;
79   InitSecContextMock::input_chan_bindings = input_chan_bindings;
80   InitSecContextMock::input_token.length = input_token->length;
81   InitSecContextMock::input_token.value = input_token->value;
82   
83   
84   /* Copy out the output from this function */
85   *minor_status = InitSecContextMock::minor_status;
86   *actual_mech_type = InitSecContextMock::actual_mech_type;
87   output_token->length = InitSecContextMock::output_token.length;
88   output_token->value = InitSecContextMock::output_token.value;
89   *ret_flags = InitSecContextMock::ret_flags;
90   *time_rec = InitSecContextMock::time_rec;
91   
92   /* Handle the one that's I/O */
93   tmpContext = *context_handle;
94   *context_handle = InitSecContextMock::context_handle;
95   InitSecContextMock::context_handle = tmpContext;
96
97   return InitSecContextMock::retVal;
98 }
99
100
101 void
102 GSSCreateSecContextTest::setUp()
103 {
104   InitSecContextMock::reset();
105 }
106
107 void
108 GSSCreateSecContextTest::tearDown()
109 {
110 }
111
112 void
113 GSSCreateSecContextTest::testConstructor()
114 {
115   GSSInitSecContext cmd = GSSInitSecContext();
116   init_sec_context_type cmdFn;
117   init_sec_context_type GSSFn;
118   
119   cmdFn = cmd.getGSSFunction();
120   GSSFn = &gss_init_sec_context;
121   CPPUNIT_ASSERT_MESSAGE(
122     "The default constructor for GSSCreateSecContextCommand should assign the function gss_init_sec_context", 
123     cmdFn == GSSFn);
124   
125   // Check that we defaut to the moonshot OID
126   CPPUNIT_ASSERT_EQUAL_MESSAGE(
127     "The mech_type default value is unexpected.",
128     std::string("{ 1 3 6 1 5 5 15 1 1 18 }"),
129     cmd.getMechType().toString()
130   );
131 }
132
133 /* JSON Input:
134  * { 
135  *   "method": "gss_create_sec_context",
136  *   "arguments": 
137  *   {
138  *     "req_flags": "1",
139  *     "time_req": "2",
140  *     "mech_type": "{ 1 2 840 113554 1 2 1 4 }",
141  *     "target_name": "me@my.sha/DOW"
142  *   }
143  * }
144  */
145 void GSSCreateSecContextTest::testConstructorWithJSONObject()
146 {
147   OM_uint32 major, minor;
148   gss_name_t src;
149   GSSName source;
150   char *source_name = (char *)"HTTP@localhost\0";
151   
152   
153   major = gss_import_name(&minor, GSSBuffer(source_name).toGss(), GSS_C_NT_HOSTBASED_SERVICE, &src);
154   if (GSS_ERROR(major))
155   {
156     OM_uint32 min, context;
157     gss_buffer_desc buf;
158     
159     std::cout << "Error in importing name." << std::endl;
160     gss_display_status(&min, major, GSS_C_GSS_CODE, GSS_C_NT_HOSTBASED_SERVICE, &context, &buf);
161     std::cout << "  message: " << (char *)buf.value << std::endl;
162   }
163   CPPUNIT_ASSERT_MESSAGE(
164     "Could not generate a name to test GSSCreateSecContext JSON parsing.",
165     !GSS_ERROR(major)
166   );
167   source.setValue(src);
168   std::string key = GSSNameCache::instance()->store(source);
169
170   std::string input = "{\"req_flags\": \"1\", \
171     \"time_req\": \"2\", \
172     \"mech_type\": \"{ 1 2 840 113554 1 2 1 4 }\", \
173     \"target_name\": \"";
174   input = input + key + "\"}";
175
176   json_error_t jsonErr;
177   const char *in = input.c_str();
178   JSONObject json = JSONObject::load(in, 0, &jsonErr);
179   
180   GSSInitSecContext cmd = GSSInitSecContext(
181     &json, 
182     &mock_init_sec
183   );
184
185   const char *from_cmd = cmd.getTargetDisplayName();
186   
187   CPPUNIT_ASSERT_MESSAGE(
188     "The object does not have a target name.",
189     ( strcmp(source_name, from_cmd) == 0 )
190   );
191   
192   CPPUNIT_ASSERT_EQUAL_MESSAGE(
193     "The context_handle values differ.",
194     json["context_handle"].integer(),
195     (json_int_t)cmd.getContextHandle()
196   );
197   
198   CPPUNIT_ASSERT_EQUAL_MESSAGE(
199     "The mech_type values differ.",
200     std::string(json["mech_type"].string()), 
201     cmd.getMechType().toString()
202   );
203   
204   CPPUNIT_ASSERT_EQUAL_MESSAGE(
205     "The req_flags differ.",
206     (int)json["req_flags"].integer(),
207     (int)cmd.getReqFlags()
208   );
209   
210   CPPUNIT_ASSERT_EQUAL_MESSAGE(
211     "The req_flags differ.",
212     (int)json["time_req"].integer(),
213     (int)cmd.getTimeReq()
214   );
215   
216 }
217
218 void
219 GSSCreateSecContextTest::testEmptyCall()
220 {
221   gss_ctx_id_t expectedResult, expectedArgument;
222   
223   GSSInitSecContext cmd (&mock_init_sec);
224   
225   /* Set expectations on what the GSS function will be called with */
226   cmd.time_req = rand() % 1024;
227   cmd.req_flags = rand() % 1024;
228   cmd.target_name = NULL;
229   cmd.context_handle = expectedArgument = (gss_ctx_id_t)(long)rand();
230   
231   
232   
233   /* Set expectations on what the GSS function will produce */
234   InitSecContextMock::retVal = rand() % 1024;
235   InitSecContextMock::minor_status = rand() % 1024;
236   InitSecContextMock::context_handle = expectedResult = (gss_ctx_id_t)(long)rand();
237   InitSecContextMock::actual_mech_type = NULL;
238   InitSecContextMock::output_token.value = (void *)"http@project-moonshot.org/PROJECT-MOONSHOT.ORG\0";
239   InitSecContextMock::output_token.length = strlen((char *)InitSecContextMock::output_token.value);
240   InitSecContextMock::ret_flags = rand() % 1024;
241   InitSecContextMock::time_req = rand() % 1024;
242   
243   cmd.execute();
244   
245   /* Check that init_sec_context's inputs are sent correctly */
246   CPPUNIT_ASSERT_MESSAGE(
247     "The GSS function was not invoked!",
248     InitSecContextMock::visited
249   );
250   CPPUNIT_ASSERT_EQUAL_MESSAGE(
251     "The time_req field was not used in the call to init_sec_context",
252     cmd.time_req,
253     InitSecContextMock::time_req
254   );
255   CPPUNIT_ASSERT_EQUAL_MESSAGE(
256     "The req_flags field was not used in the call to init_sec_context",
257     cmd.req_flags,
258     InitSecContextMock::req_flags
259   );
260   CPPUNIT_ASSERT_EQUAL_MESSAGE(
261     "The mech_type field was not used in the call to init_sec_context",
262     cmd.getMechType().toGss(),
263     InitSecContextMock::mech_type
264   );
265   CPPUNIT_ASSERT_EQUAL_MESSAGE(
266     "The target_name field was not used in the call to init_sec_context",
267     cmd.target_name,
268     InitSecContextMock::target_name
269   );
270   
271   
272   /* Check that init_sec_context's outputs are captured correctly */
273   CPPUNIT_ASSERT_EQUAL_MESSAGE(
274     "Return value was not copied back to the command.",
275     InitSecContextMock::retVal,
276     cmd.retVal
277   );
278   CPPUNIT_ASSERT_EQUAL_MESSAGE(
279     "Status was not copied back to the command.",
280     InitSecContextMock::minor_status,
281     cmd.minor_status
282   );
283   CPPUNIT_ASSERT_EQUAL_MESSAGE(
284     "context_handle was not copied back to the command.",
285     expectedResult,
286     cmd.context_handle
287   );
288   CPPUNIT_ASSERT_EQUAL_MESSAGE(
289     "context_handle was not copied back to the command.",
290     expectedArgument,
291     InitSecContextMock::context_handle
292   );
293   CPPUNIT_ASSERT_EQUAL_MESSAGE(
294     "actual_mech_type was not copied back to the command.",
295     InitSecContextMock::actual_mech_type,
296     cmd.getActualMechType().toGss()
297   );
298   CPPUNIT_ASSERT_EQUAL_MESSAGE(
299     "output_token was not copied back to the command.",
300     InitSecContextMock::output_token.value,
301     cmd.output_token.value
302   );
303   CPPUNIT_ASSERT_EQUAL_MESSAGE(
304     "ret_flags was not copied back to the command.",
305     InitSecContextMock::ret_flags,
306     cmd.ret_flags
307   );
308   CPPUNIT_ASSERT_EQUAL_MESSAGE(
309     "time_rec was not copied back to the command.",
310     InitSecContextMock::time_rec,
311     cmd.time_rec
312   );
313   
314   // Set this to no context, or cleanup attempts to free the not-a-real-pointer.
315   InitSecContextMock::context_handle = GSS_C_NO_CONTEXT;
316   
317 }
318
319 /* Expected JSON output:
320  * 
321  * {
322  *   "command": "gss_init_sec_context", 
323  *   "return_values": 
324  *   {
325  *     "context_handle": "base64_encoded_string", 
326  *     "major_status": ##, 
327  *     "output_token": "http@project-moonshot.org/PROJECT-MOONSHOT.ORG", 
328  *     "actual_mech_type": "{ 1 3 6 1 5 5 13 4 }", 
329  *     "minor_status": ##, 
330  *     ret_flags": ##, 
331  *     "time_rec": ##
332  *   }
333  * }
334  * 
335  */
336 void GSSCreateSecContextTest::testJSONMarshal()
337 {
338   /* Variables */
339   GSSInitSecContext cmd (&mock_init_sec);
340   JSONObject *result;
341   GSSContextCache *cache = GSSContextCache::instance();
342   GSSContext context;
343   gss_ctx_id_t expectedResult;
344   
345   /* Error checking */
346   
347   /* Setup */
348   // Set expectations on what the GSS function will produce
349   InitSecContextMock::retVal = GSS_S_CONTINUE_NEEDED;
350   InitSecContextMock::minor_status = 0;
351   InitSecContextMock::context_handle = expectedResult = (gss_ctx_id_t)(long)rand();
352   InitSecContextMock::actual_mech_type = (gss_OID)GSS_C_MA_MECH_NEGO;
353   InitSecContextMock::output_token.value = (void *)"http@project-moonshot.org/PROJECT-MOONSHOT.ORG\0";
354   InitSecContextMock::output_token.length = strlen((char *)InitSecContextMock::output_token.value);
355   InitSecContextMock::ret_flags = GSS_C_MUTUAL_FLAG | 
356       GSS_C_REPLAY_FLAG | 
357       GSS_C_SEQUENCE_FLAG | 
358       GSS_C_CONF_FLAG | 
359       GSS_C_INTEG_FLAG | 
360       GSS_C_ANON_FLAG | 
361       GSS_C_PROT_READY_FLAG;
362   InitSecContextMock::time_req = GSS_C_INDEFINITE;
363   
364   /* Main */
365   cmd.execute();
366   result = cmd.toJSON();
367 /*  
368   std::cout << "create sec context json: " << result->dump() << "\n";*/
369   
370   CPPUNIT_ASSERT_EQUAL_MESSAGE(
371     "The return value was reported incorrectly",
372     (int)InitSecContextMock::retVal,
373     (int)( (*result)["major_status"].integer() )
374   );
375   
376   CPPUNIT_ASSERT_EQUAL_MESSAGE(
377     "The minor_status value was reported incorrectly",
378     (int)InitSecContextMock::minor_status,
379     (int)( (*result)["minor_status"].integer() )
380   );
381   
382   CPPUNIT_ASSERT_MESSAGE(
383     "The actual_mech_type value was reported incorrectly",
384     ( strcmp("{ 1 3 6 1 5 5 13 4 }", 
385              (*result)["actual_mech_type"].string() ) == 0 )
386   );
387
388   
389   
390   std::string str = (*result)["output_token"].string();
391   size_t len;
392   void *decoded = base64Decode(str.c_str(), &len);
393   CPPUNIT_ASSERT_MESSAGE(
394     "The decoded token size is incorrect",
395     ( len == InitSecContextMock::output_token.length )
396   );
397   CPPUNIT_ASSERT_MESSAGE(
398     "The output_token value was reported incorrectly",
399     ( memcmp(InitSecContextMock::output_token.value,
400              decoded, len ) == 0 )
401   );
402   base64Free(decoded);
403   
404   CPPUNIT_ASSERT_EQUAL_MESSAGE(
405     "The minor_status value was reported incorrectly",
406     (int)InitSecContextMock::ret_flags,
407     (int)( (*result)["ret_flags"].integer() )
408   );
409   
410   CPPUNIT_ASSERT_EQUAL_MESSAGE(
411     "The minor_status value was reported incorrectly",
412     (int)InitSecContextMock::time_rec,
413     (int)( (*result)["time_rec"].integer() )
414   );
415   
416   context = cache->retrieve( (*result)["context_handle"].string() );
417   
418   CPPUNIT_ASSERT_EQUAL_MESSAGE(
419     "The returned context was reported incorrectly",
420     (long)expectedResult,
421     (long)context.getContext()
422   );
423   
424   /* Cleanup */
425   /* Return */
426 }
427
428