Updated Easysetup Security logic.
[platform/upstream/iotivity.git] / service / easy-setup / mediator / richsdk / src / RemoteEnrollee.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "RemoteEnrollee.h"
22 #include "EnrolleeResource.h"
23 #include "CloudResource.h"
24 #include "OCPlatform.h"
25 #include "ESException.h"
26 #include "logger.h"
27 #include "OCResource.h"
28 #ifdef __WITH_DTLS__
29 #include "EnrolleeSecurity.h"
30 #include "base64.h"
31 #include "oic_malloc.h"
32 #endif //__WITH_DTLS
33
34 namespace OIC
35 {
36     namespace Service
37     {
38         static const char ES_BASE_RES_URI[] = "/oic/res";
39         #define ES_REMOTE_ENROLLEE_TAG "ES_REMOTE_ENROLLEE"
40         #define DISCOVERY_TIMEOUT 5
41
42         RemoteEnrollee::RemoteEnrollee(const std::shared_ptr< OC::OCResource > resource)
43         {
44             m_ocResource = resource;
45             m_enrolleeResource = std::make_shared<EnrolleeResource>(m_ocResource);
46             m_securityProvStatusCb = nullptr;
47             m_getConfigurationStatusCb = nullptr;
48             m_securityPinCb = nullptr;
49             m_secProvisioningDbPathCb = nullptr;
50             m_devicePropProvStatusCb = nullptr;
51             m_cloudPropProvStatusCb = nullptr;
52
53             m_deviceId = resource->sid();
54         }
55
56         void RemoteEnrollee::securityStatusHandler(
57                 const std::shared_ptr< SecProvisioningStatus > status) const
58         {
59             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s,"
60                     "Status = %d", status->getDeviceUUID().c_str(),
61                     status->getESResult());
62
63             if(status->getESResult() == ES_OK)
64             {
65                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
66                         "Continue with Network information provisioning");
67
68                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before provisionProperties");
69
70                 m_securityProvStatusCb(status);
71             }
72             else
73             {
74                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are fail");
75
76                 m_securityProvStatusCb(status);
77             }
78         }
79
80         void RemoteEnrollee::getStatusHandler(
81                 const std::shared_ptr< GetEnrolleeStatus > status) const
82         {
83             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getStatusHandler");
84
85             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"getStatusHandler = %d", status->getESResult());
86
87             m_getStatusCb(status);
88         }
89
90         void RemoteEnrollee::getConfigurationStatusHandler (
91                 const std::shared_ptr< GetConfigurationStatus > status) const
92         {
93             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getConfigurationStatusHandler");
94
95             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d",
96                                                     status->getESResult());
97
98             m_getConfigurationStatusCb(status);
99         }
100
101         void RemoteEnrollee::devicePropProvisioningStatusHandler(
102                 const std::shared_ptr< DevicePropProvisioningStatus > status) const
103         {
104             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering DevicePropProvisioningStatusHandler");
105
106             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
107
108             m_devicePropProvStatusCb(status);
109
110             return;
111         }
112
113         void RemoteEnrollee::cloudPropProvisioningStatusHandler (
114                 const std::shared_ptr< CloudPropProvisioningStatus > status) const
115         {
116             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudPropProvisioningStatusHandler");
117
118             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d",
119                                                     status->getESResult());
120
121             m_cloudPropProvStatusCb(status);
122             return;
123         }
124
125         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
126         {
127             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
128
129             std::string resourceURI;
130             std::string hostAddress;
131             std::string hostDeviceID;
132
133             try
134             {
135                 if(resource)
136                 {
137                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
138                     {
139                         // Get the resource URI
140                         resourceURI = resource->uri();
141                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
142                                 "URI of the resource: %s", resourceURI.c_str());
143
144                         // Get the resource host address
145                         hostAddress = resource->host();
146                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
147                                 "Host address of the resource: %s", hostAddress.c_str());
148
149                         hostDeviceID = resource->sid();
150                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
151                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
152
153                         if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
154                         {
155                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
156                             m_ocResource = resource;
157                             m_discoveryResponse = true;
158                             m_cond.notify_all();
159                         }
160                     }
161                 }
162             }
163             catch(std::exception& e)
164             {
165                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
166                         "Exception in foundResource: %s", e.what());
167             }
168         }
169
170         ESResult RemoteEnrollee::discoverResource()
171         {
172             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
173
174             std::string query("");
175             query.append(ES_BASE_RES_URI);
176             query.append("?rt=");
177             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
178
179             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
180
181             m_discoveryResponse = false;
182
183             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
184                     std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
185                                                     std::placeholders::_1);
186             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
187                     onDeviceDiscoveredCb);
188
189             if (result != OCStackResult::OC_STACK_OK)
190             {
191                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
192                         "Failed discoverResource");
193                 return ES_ERROR;
194             }
195
196             std::unique_lock<std::mutex> lck(m_discoverymtx);
197             m_cond.wait_for(lck, std::chrono::seconds(DISCOVERY_TIMEOUT));
198
199             if (!m_discoveryResponse)
200             {
201                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
202                         "Failed discoverResource because timeout");
203                 return ES_ERROR;
204             }
205             return ES_OK;
206         }
207
208         void RemoteEnrollee::provisionSecurity(const SecurityProvStatusCb callback)
209         {
210 #ifdef __WITH_DTLS__
211             ESResult res = ESResult::ES_ERROR;
212             if(!callback)
213             {
214                 throw ESInvalidParameterException("Callback is empty");
215             }
216             m_securityProvStatusCb = callback;
217
218             SecurityProvStatusCb securityProvStatusCb = std::bind(
219                     &RemoteEnrollee::securityStatusHandler,
220                     this,
221                     std::placeholders::_1);
222             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
223             if(!m_enrolleeSecurity.get())
224             {
225                 m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
226             }
227
228             res = m_enrolleeSecurity->provisionOwnership();
229
230             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
231                             std::make_shared< SecProvisioningStatus >(m_enrolleeSecurity->getUUID(), res);
232             m_securityProvStatusCb(securityProvisioningStatus);
233             m_enrolleeSecurity.reset();
234 #else
235             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
236             if(!callback)
237             {
238                 throw ESInvalidParameterException("Callback is empty");
239             }
240             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
241                      std::make_shared< SecProvisioningStatus >
242                                    ("", ESResult::ES_SEC_OPERATION_IS_NOT_SUPPORTED);
243             callback(securityProvisioningStatus);
244 #endif
245         }
246
247         void RemoteEnrollee::getStatus(const GetStatusCb callback)
248         {
249             if(!callback)
250             {
251                 throw ESInvalidParameterException("Callback is empty");
252             }
253
254             if (m_enrolleeResource == nullptr)
255             {
256                 throw ESBadRequestException ("Device not created");
257             }
258
259             m_getStatusCb = callback;
260
261             GetStatusCb getStatusCb = std::bind(
262                 &RemoteEnrollee::getStatusHandler, this, std::placeholders::_1);
263             m_enrolleeResource->registerGetStatusCallback(getStatusCb);
264             m_enrolleeResource->getStatus();
265
266         }
267
268         void RemoteEnrollee::getConfiguration(const GetConfigurationStatusCb callback)
269         {
270             if(!callback)
271             {
272                 throw ESInvalidParameterException("Callback is empty");
273             }
274
275             if (m_enrolleeResource == nullptr)
276             {
277                 throw ESBadRequestException ("Device not created");
278             }
279
280             m_getConfigurationStatusCb = callback;
281
282             GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
283                     &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
284             m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
285             m_enrolleeResource->getConfiguration();
286         }
287
288         void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& deviceProp,
289                                                             const DevicePropProvStatusCb callback)
290         {
291             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionDeviceProperties");
292
293             if(!callback)
294             {
295                 throw ESInvalidParameterException("Callback is empty");
296             }
297
298             m_devicePropProvStatusCb = callback;
299
300             if (m_enrolleeResource == nullptr)
301             {
302                 throw ESBadRequestException ("Device not created");
303             }
304
305             if(deviceProp.getSsid().empty())
306             {
307                 throw ESBadRequestException ("Invalid Provisiong Data.");
308             }
309
310             DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
311                     &RemoteEnrollee::devicePropProvisioningStatusHandler,
312                     this, std::placeholders::_1);
313
314             m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
315             m_enrolleeResource->provisionProperties(deviceProp);
316         }
317
318         void RemoteEnrollee::initCloudResource()
319         {
320             ESResult result = ES_ERROR;
321
322             result = discoverResource();
323
324             if (result == ES_ERROR)
325             {
326                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
327                                     "Failed to create resource object using discoverResource");
328                 throw ESBadRequestException ("Resource object not created");
329             }
330
331             else
332             {
333                 if(m_ocResource != nullptr)
334                 {
335                     m_cloudResource = std::make_shared<CloudResource>(m_ocResource);
336                 }
337                 else
338                 {
339                     throw ESBadGetException ("Resource handle is invalid");
340                 }
341             }
342         }
343
344         void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp,
345                                                             const CloudPropProvStatusCb callback)
346         {
347             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionCloudProperties");
348
349             if(!callback)
350             {
351                 throw ESInvalidParameterException("Callback is empty");
352             }
353
354             m_cloudPropProvStatusCb = callback;
355
356             if(cloudProp.getAuthCode().empty() ||
357                 cloudProp.getAuthProvider().empty() ||
358                 cloudProp.getCiServer().empty())
359             {
360                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
361             }
362
363             try
364             {
365                 initCloudResource();
366             }
367
368             catch (const std::exception& e)
369             {
370                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
371                     "Exception caught in provisionCloudProperties = %s", e.what());
372
373                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
374                         CloudPropProvisioningStatus >(ESResult::ES_ENROLLEE_DISCOVERY_FAILURE);
375                 m_cloudPropProvStatusCb(provStatus);
376                 return;
377             }
378 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
379             if(!(cloudProp.getCloudID().empty() && cloudProp.getCredID() <= 0))
380             {
381                 ESResult res = ESResult::ES_ERROR;
382                 if(!m_enrolleeSecurity.get())
383                 {
384                     m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
385                 }
386
387
388                 res = m_enrolleeSecurity->provisionSecurityForCloudServer(cloudProp.getCloudID(),
389                                                                           cloudProp.getCredID());
390                 m_enrolleeSecurity.reset();
391                 if(res != ESResult::ES_OK)
392                 {
393                     m_cloudResource = nullptr;
394                     std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
395                             CloudPropProvisioningStatus >(res);
396                     m_cloudPropProvStatusCb(provStatus);
397                     return;
398                 }
399             }
400             else
401             {
402                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "ACL and Cert. provisioning are skipped.");
403             }
404 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)
405
406             if (m_cloudResource == nullptr)
407             {
408                 throw ESBadRequestException ("Cloud Resource not created");
409             }
410
411             CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
412                     &RemoteEnrollee::cloudPropProvisioningStatusHandler,
413                                     this, std::placeholders::_1);
414
415             m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
416             m_cloudResource->provisionProperties(cloudProp);
417         }
418     }
419 }