Merge branch 'master' into extended-easysetup
[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(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 #ifdef __WITH_DTLS__
57         ESResult RemoteEnrollee::registerSecurityCallbackHandler(SecurityPinCb securityPinCb,
58                 SecProvisioningDbPathCb secProvisioningDbPathCb)
59         {
60             // No need to check NULL for m_secProvisioningDbPathCB as this is not a mandatory
61             // callback function. If m_secProvisioningDbPathCB is NULL, provisioning manager
62             // in security layer will try to find the PDM.db file in the local path.
63             // If PDM.db is found, the provisioning manager operations will succeed.
64             // Otherwise all the provisioning manager operations will fail.
65             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
66             m_securityPinCb = securityPinCb;
67             return ES_OK;
68         }
69 #endif //__WITH_DTLS__
70
71         void RemoteEnrollee::securityStatusHandler(
72                         std::shared_ptr< SecProvisioningStatus > status)
73         {
74             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s,"
75                     "Status = %d", status->getDeviceUUID().c_str(),
76                     status->getESResult());
77
78             if(status->getESResult() == ES_OK)
79             {
80                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
81                         "Continue with Network information provisioning");
82
83                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
84
85                 m_securityProvStatusCb(status);
86             }
87             else
88             {
89                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are fail");
90
91                 m_securityProvStatusCb(status);
92             }
93         }
94
95         void RemoteEnrollee::getStatusHandler(std::shared_ptr< GetEnrolleeStatus > status)
96         {
97             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getStatusHandler");
98
99             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"getStatusHandler = %d", status->getESResult());
100
101             m_getStatusCb(status);
102         }
103
104         void RemoteEnrollee::getConfigurationStatusHandler (
105                 std::shared_ptr< GetConfigurationStatus > status)
106         {
107             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getConfigurationStatusHandler");
108
109             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d",
110                                                     status->getESResult());
111
112             m_getConfigurationStatusCb(status);
113         }
114
115         void RemoteEnrollee::devicePropProvisioningStatusHandler(
116                 std::shared_ptr< DevicePropProvisioningStatus > status)
117         {
118             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering DevicePropProvisioningStatusHandler");
119
120             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
121
122             m_devicePropProvStatusCb(status);
123
124             return;
125         }
126
127         void RemoteEnrollee::cloudPropProvisioningStatusHandler (
128                 std::shared_ptr< CloudPropProvisioningStatus > status)
129         {
130             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudPropProvisioningStatusHandler");
131
132             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d",
133                                                     status->getESCloudState());
134
135             m_cloudPropProvStatusCb(status);
136             return;
137         }
138
139         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
140         {
141             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
142
143             std::string resourceURI;
144             std::string hostAddress;
145             std::string hostDeviceID;
146
147             try
148             {
149                 if(resource)
150                 {
151                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
152                     {
153                         // Get the resource URI
154                         resourceURI = resource->uri();
155                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
156                                 "URI of the resource: %s", resourceURI.c_str());
157
158                         // Get the resource host address
159                         hostAddress = resource->host();
160                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
161                                 "Host address of the resource: %s", hostAddress.c_str());
162
163                         hostDeviceID = resource->sid();
164                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
165                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
166
167                         if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
168                         {
169                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
170                             m_ocResource = resource;
171                             m_discoveryResponse = true;
172                             m_cond.notify_all();
173                         }
174                     }
175                 }
176             }
177             catch(std::exception& e)
178             {
179                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
180                         "Exception in foundResource: %s", e.what());
181             }
182         }
183
184         ESResult RemoteEnrollee::discoverResource()
185         {
186             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
187
188             std::string query("");
189             query.append(ES_BASE_RES_URI);
190             query.append("?rt=");
191             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
192
193             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
194
195             m_discoveryResponse = false;
196
197             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
198                     std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
199                                                     std::placeholders::_1);
200             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
201                     onDeviceDiscoveredCb);
202
203             if (result != OCStackResult::OC_STACK_OK)
204             {
205                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
206                         "Failed discoverResource");
207                 return ES_ERROR;
208             }
209
210             std::unique_lock<std::mutex> lck(m_discoverymtx);
211             m_cond.wait_for(lck, std::chrono::seconds(DISCOVERY_TIMEOUT));
212
213             if (!m_discoveryResponse)
214             {
215                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
216                         "Failed discoverResource because timeout");
217                 return ES_ERROR;
218             }
219             return ES_OK;
220         }
221
222         void RemoteEnrollee::provisionSecurity(SecurityProvStatusCb callback)
223         {
224 #ifdef __WITH_DTLS__
225             m_securityProvStatusCb = callback;
226
227             SecurityProvStatusCb securityProvStatusCb = std::bind(
228                     &RemoteEnrollee::securityStatusHandler,
229                     this,
230                     std::placeholders::_1);
231             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
232             m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
233
234             m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb, m_securityPinCb,
235                                                         m_secProvisioningDbPathCb);
236
237             try
238             {
239                 m_enrolleeSecurity->performOwnershipTransfer();
240             }
241             catch (const std::exception& e)
242             {
243                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
244                         "Exception for performOwnershipTransfer : %s", e.what());
245
246                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Fail performOwnershipTransfer");
247                 std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
248                         std::make_shared< SecProvisioningStatus >
249                                                         (m_enrolleeSecurity->getUUID(), ES_ERROR);
250                     m_securityProvStatusCb(securityProvisioningStatus);
251                 return ;
252             }
253 #else
254             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
255
256             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
257                      std::make_shared< SecProvisioningStatus >
258                                                         ("", ES_UNSUPPORTED_OPERATION);
259             m_securityProvStatusCb(securityProvisioningStatus);
260 #endif
261         }
262
263         void RemoteEnrollee::getStatus(GetStatusCb callback)
264         {
265             if(!callback)
266             {
267                 throw ESInvalidParameterException("Callback is empty");
268             }
269
270             if (m_enrolleeResource == nullptr)
271             {
272                 throw ESBadRequestException ("Device not created");
273             }
274
275             m_getStatusCb = callback;
276
277             GetStatusCb getStatusCb = std::bind(
278                 &RemoteEnrollee::getStatusHandler, this, std::placeholders::_1);
279             m_enrolleeResource->registerGetStatusCallback(getStatusCb);
280             m_enrolleeResource->getStatus();
281
282         }
283
284         void RemoteEnrollee::getConfiguration(GetConfigurationStatusCb callback)
285         {
286             if(!callback)
287             {
288                 throw ESInvalidParameterException("Callback is empty");
289             }
290
291             if (m_enrolleeResource == nullptr)
292             {
293                 throw ESBadRequestException ("Device not created");
294             }
295
296             m_getConfigurationStatusCb = callback;
297
298             GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
299                     &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
300             m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
301             m_enrolleeResource->getConfiguration();
302         }
303
304         void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& deviceProp,
305                                                             DevicePropProvStatusCb callback)
306         {
307             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionDeviceProperties");
308
309             if(!callback)
310             {
311                 throw ESInvalidParameterException("Callback is empty");
312             }
313
314             m_devicePropProvStatusCb = callback;
315
316             if (m_enrolleeResource == nullptr)
317             {
318                 throw ESBadRequestException ("Device not created");
319             }
320
321             if(!deviceProp.toOCRepresentation().hasAttribute(OC_RSRVD_ES_SSID))
322             {
323                 throw ESBadRequestException ("Invalid Provisiong Data.");
324             }
325
326             DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
327                     &RemoteEnrollee::devicePropProvisioningStatusHandler,
328                     this, std::placeholders::_1);
329
330             m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
331             m_enrolleeResource->provisionEnrollee(deviceProp);
332         }
333
334         void RemoteEnrollee::initCloudResource()
335         {
336             ESResult result = ES_ERROR;
337
338             if (m_cloudResource != nullptr)
339             {
340                 throw ESBadRequestException ("Already created");
341             }
342
343             result = discoverResource();
344
345             if (result == ES_ERROR)
346             {
347                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
348                                     "Failed to create resource object using discoverResource");
349                 throw ESBadRequestException ("Resource object not created");
350             }
351
352             else
353             {
354                 if(m_ocResource != nullptr)
355                 {
356                     m_cloudResource = std::make_shared<CloudResource>(m_ocResource);
357
358                     std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
359                         CloudPropProvisioningStatus >(ESResult::ES_OK,
360                                                         ESCloudProvState::ES_CLOUD_ENROLLEE_FOUND);
361
362                     m_cloudPropProvStatusCb(provStatus);
363                 }
364                 else
365                 {
366                     throw ESBadGetException ("Resource handle is invalid");
367                 }
368             }
369         }
370
371         void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp,
372                                                             CloudPropProvStatusCb callback)
373         {
374             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionCloudProperties");
375             ESResult res = ES_OK;
376
377             if(!callback)
378             {
379                 throw ESInvalidParameterException("Callback is empty");
380             }
381
382             m_cloudPropProvStatusCb = callback;
383
384             if(!cloudProp.toOCRepresentation().hasAttribute(OC_RSRVD_ES_AUTHCODE) ||
385                 !cloudProp.toOCRepresentation().hasAttribute(OC_RSRVD_ES_AUTHPROVIDER) ||
386                 !cloudProp.toOCRepresentation().hasAttribute(OC_RSRVD_ES_CISERVER))
387             {
388                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
389             }
390
391             try
392             {
393                 initCloudResource();
394             }
395
396             catch (const std::exception& e)
397             {
398                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
399                     "Exception caught in provisionCloudProperties = %s", e.what());
400
401                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
402                         CloudPropProvisioningStatus >(ESResult::ES_ERROR,
403                                                     ESCloudProvState::ES_CLOUD_ENROLLEE_NOT_FOUND);
404                 m_cloudPropProvStatusCb(provStatus);
405                 return;
406             }
407
408 #ifdef __WITH_DTLS__
409             try
410             {
411                 m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
412
413                 if(cloudProp.getCloudID().empty())
414                 {
415                     throw ESBadRequestException("Invalid Cloud Server UUID.");
416                 }
417
418                 res = m_enrolleeSecurity->performACLProvisioningForCloudServer(cloudProp.getCloudID());
419
420                 if(res == ESResult::ES_ERROR)
421                 {
422                     throw ESBadRequestException("Error in provisioning operation!");
423                 }
424
425             }
426
427             catch (const std::exception& e)
428             {
429                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
430                     "Exception caught in provisionCloudProperties = %s", e.what());
431
432                 m_cloudResource = nullptr;
433
434                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
435                         CloudPropProvisioningStatus >(ESResult::ES_ERROR,
436                                                     ESCloudProvState::ES_CLOUD_PROVISIONING_ERROR);
437                 m_cloudPropProvStatusCb(provStatus);
438                 return;
439             }
440 #endif
441
442             if (m_cloudResource == nullptr)
443             {
444                 throw ESBadRequestException ("Cloud Resource not created");
445             }
446
447             CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
448                     &RemoteEnrollee::cloudPropProvisioningStatusHandler,
449                                     this, std::placeholders::_1);
450
451             m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
452             m_cloudResource->provisionEnrollee(cloudProp);
453         }
454     }
455 }