Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

This library implements the AMQP transport for Microsoft Azure IoTHub client. The code is replicated from https://github.com/Azure/azure-iot-sdks

Committer:
AzureIoTClient
Date:
Fri Mar 24 16:35:00 2017 -0700
Revision:
31:adadaef857c1
Parent:
30:20a85b733111
Child:
34:51d158b409d2
1.1.10

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 30:20a85b733111 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 30:20a85b733111 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 30:20a85b733111 3
AzureIoTClient 30:20a85b733111 4 #include <stdlib.h>
AzureIoTClient 30:20a85b733111 5 #include "iothubtransport_amqp_cbs_auth.h"
AzureIoTClient 30:20a85b733111 6 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 30:20a85b733111 7 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 30:20a85b733111 8 #include "azure_c_shared_utility/agenttime.h"
AzureIoTClient 30:20a85b733111 9 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 30:20a85b733111 10 #include "azure_c_shared_utility/sastoken.h"
AzureIoTClient 30:20a85b733111 11
AzureIoTClient 30:20a85b733111 12 #define RESULT_OK 0
AzureIoTClient 30:20a85b733111 13 #define INDEFINITE_TIME ((time_t)(-1))
AzureIoTClient 30:20a85b733111 14 #define SAS_TOKEN_TYPE "servicebus.windows.net:sastoken"
AzureIoTClient 30:20a85b733111 15 #define IOTHUB_DEVICES_PATH_FMT "%s/devices/%s"
AzureIoTClient 30:20a85b733111 16 #define DEFAULT_CBS_REQUEST_TIMEOUT_SECS UINT32_MAX
AzureIoTClient 30:20a85b733111 17 #define DEFAULT_SAS_TOKEN_LIFETIME_SECS 3600
AzureIoTClient 30:20a85b733111 18 #define DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS 1800
AzureIoTClient 30:20a85b733111 19
AzureIoTClient 30:20a85b733111 20 typedef enum CREDENTIAL_TYPE_TAG
AzureIoTClient 30:20a85b733111 21 {
AzureIoTClient 30:20a85b733111 22 CREDENTIAL_TYPE_NONE,
AzureIoTClient 30:20a85b733111 23 DEVICE_PRIMARY_KEY,
AzureIoTClient 30:20a85b733111 24 DEVICE_SECONDARY_KEY,
AzureIoTClient 30:20a85b733111 25 USER_PROVIDED_SAS_TOKEN
AzureIoTClient 30:20a85b733111 26 } CREDENTIAL_TYPE;
AzureIoTClient 30:20a85b733111 27
AzureIoTClient 30:20a85b733111 28 typedef struct AUTHENTICATION_INSTANCE_TAG
AzureIoTClient 30:20a85b733111 29 {
AzureIoTClient 30:20a85b733111 30 STRING_HANDLE device_id;
AzureIoTClient 30:20a85b733111 31 STRING_HANDLE iothub_host_fqdn;
AzureIoTClient 30:20a85b733111 32
AzureIoTClient 30:20a85b733111 33 STRING_HANDLE device_sas_token;
AzureIoTClient 30:20a85b733111 34 STRING_HANDLE device_primary_key;
AzureIoTClient 30:20a85b733111 35 STRING_HANDLE device_secondary_key;
AzureIoTClient 30:20a85b733111 36
AzureIoTClient 30:20a85b733111 37 ON_AUTHENTICATION_STATE_CHANGED_CALLBACK on_state_changed_callback;
AzureIoTClient 30:20a85b733111 38 void* on_state_changed_callback_context;
AzureIoTClient 30:20a85b733111 39
AzureIoTClient 30:20a85b733111 40 ON_AUTHENTICATION_ERROR_CALLBACK on_error_callback;
AzureIoTClient 30:20a85b733111 41 void* on_error_callback_context;
AzureIoTClient 30:20a85b733111 42
AzureIoTClient 30:20a85b733111 43 size_t cbs_request_timeout_secs;
AzureIoTClient 30:20a85b733111 44 size_t sas_token_lifetime_secs;
AzureIoTClient 30:20a85b733111 45 size_t sas_token_refresh_time_secs;
AzureIoTClient 30:20a85b733111 46
AzureIoTClient 30:20a85b733111 47 AUTHENTICATION_STATE state;
AzureIoTClient 30:20a85b733111 48 CBS_HANDLE cbs_handle;
AzureIoTClient 30:20a85b733111 49
AzureIoTClient 30:20a85b733111 50 bool is_cbs_put_token_in_progress;
AzureIoTClient 30:20a85b733111 51 bool is_sas_token_refresh_in_progress;
AzureIoTClient 30:20a85b733111 52
AzureIoTClient 30:20a85b733111 53 time_t current_sas_token_put_time;
AzureIoTClient 30:20a85b733111 54
AzureIoTClient 30:20a85b733111 55 CREDENTIAL_TYPE current_credential_in_use;
AzureIoTClient 30:20a85b733111 56 } AUTHENTICATION_INSTANCE;
AzureIoTClient 30:20a85b733111 57
AzureIoTClient 30:20a85b733111 58
AzureIoTClient 30:20a85b733111 59 // Helper functions:
AzureIoTClient 30:20a85b733111 60
AzureIoTClient 30:20a85b733111 61 static int get_seconds_since_epoch(double *seconds)
AzureIoTClient 30:20a85b733111 62 {
AzureIoTClient 30:20a85b733111 63 int result;
AzureIoTClient 30:20a85b733111 64 time_t current_time;
AzureIoTClient 30:20a85b733111 65
AzureIoTClient 30:20a85b733111 66 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 67 {
AzureIoTClient 30:20a85b733111 68 LogError("Failed getting the current local time (get_time() failed)");
AzureIoTClient 30:20a85b733111 69 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 70 }
AzureIoTClient 30:20a85b733111 71 else
AzureIoTClient 30:20a85b733111 72 {
AzureIoTClient 30:20a85b733111 73 *seconds = get_difftime(current_time, (time_t)0);
AzureIoTClient 30:20a85b733111 74
AzureIoTClient 30:20a85b733111 75 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 76 }
AzureIoTClient 30:20a85b733111 77
AzureIoTClient 30:20a85b733111 78 return result;
AzureIoTClient 30:20a85b733111 79 }
AzureIoTClient 30:20a85b733111 80
AzureIoTClient 30:20a85b733111 81 static void update_state(AUTHENTICATION_INSTANCE* instance, AUTHENTICATION_STATE new_state)
AzureIoTClient 30:20a85b733111 82 {
AzureIoTClient 30:20a85b733111 83 if (new_state != instance->state)
AzureIoTClient 30:20a85b733111 84 {
AzureIoTClient 30:20a85b733111 85 AUTHENTICATION_STATE previous_state = instance->state;
AzureIoTClient 30:20a85b733111 86 instance->state = new_state;
AzureIoTClient 30:20a85b733111 87
AzureIoTClient 30:20a85b733111 88 if (instance->on_state_changed_callback != NULL)
AzureIoTClient 30:20a85b733111 89 {
AzureIoTClient 30:20a85b733111 90 instance->on_state_changed_callback(instance->on_state_changed_callback_context, previous_state, new_state);
AzureIoTClient 30:20a85b733111 91 }
AzureIoTClient 30:20a85b733111 92 }
AzureIoTClient 30:20a85b733111 93 }
AzureIoTClient 30:20a85b733111 94
AzureIoTClient 30:20a85b733111 95 static void notify_error(AUTHENTICATION_INSTANCE* instance, AUTHENTICATION_ERROR_CODE error_code)
AzureIoTClient 30:20a85b733111 96 {
AzureIoTClient 30:20a85b733111 97 if (instance->on_error_callback != NULL)
AzureIoTClient 30:20a85b733111 98 {
AzureIoTClient 30:20a85b733111 99 instance->on_error_callback(instance->on_error_callback_context, error_code);
AzureIoTClient 30:20a85b733111 100 }
AzureIoTClient 30:20a85b733111 101 }
AzureIoTClient 30:20a85b733111 102
AzureIoTClient 30:20a85b733111 103 static int verify_cbs_put_token_timeout(AUTHENTICATION_INSTANCE* instance, bool* is_timed_out)
AzureIoTClient 30:20a85b733111 104 {
AzureIoTClient 30:20a85b733111 105 int result;
AzureIoTClient 30:20a85b733111 106
AzureIoTClient 30:20a85b733111 107 if (instance->current_sas_token_put_time == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 108 {
AzureIoTClient 30:20a85b733111 109 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 110 LogError("Failed verifying if cbs_put_token has timed out (current_sas_token_put_time is not set)");
AzureIoTClient 30:20a85b733111 111 }
AzureIoTClient 30:20a85b733111 112 else
AzureIoTClient 30:20a85b733111 113 {
AzureIoTClient 30:20a85b733111 114 time_t current_time;
AzureIoTClient 30:20a85b733111 115
AzureIoTClient 30:20a85b733111 116 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 117 {
AzureIoTClient 30:20a85b733111 118 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 119 LogError("Failed verifying if cbs_put_token has timed out (get_time failed)");
AzureIoTClient 30:20a85b733111 120 }
AzureIoTClient 30:20a85b733111 121 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_083: [authentication_do_work() shall check for authentication timeout comparing the current time since `instance->current_sas_token_put_time` to `instance->cbs_request_timeout_secs`]
AzureIoTClient 30:20a85b733111 122 else if ((uint32_t)get_difftime(current_time, instance->current_sas_token_put_time) >= instance->cbs_request_timeout_secs)
AzureIoTClient 30:20a85b733111 123 {
AzureIoTClient 30:20a85b733111 124 *is_timed_out = true;
AzureIoTClient 30:20a85b733111 125 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 126 }
AzureIoTClient 30:20a85b733111 127 else
AzureIoTClient 30:20a85b733111 128 {
AzureIoTClient 30:20a85b733111 129 *is_timed_out = false;
AzureIoTClient 30:20a85b733111 130 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 131 }
AzureIoTClient 30:20a85b733111 132 }
AzureIoTClient 30:20a85b733111 133
AzureIoTClient 30:20a85b733111 134 return result;
AzureIoTClient 30:20a85b733111 135 }
AzureIoTClient 30:20a85b733111 136
AzureIoTClient 30:20a85b733111 137 static int verify_sas_token_refresh_timeout(AUTHENTICATION_INSTANCE* instance, bool* is_timed_out)
AzureIoTClient 30:20a85b733111 138 {
AzureIoTClient 30:20a85b733111 139 int result;
AzureIoTClient 30:20a85b733111 140
AzureIoTClient 30:20a85b733111 141 if (instance->current_sas_token_put_time == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 142 {
AzureIoTClient 30:20a85b733111 143 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 144 LogError("Failed verifying if SAS token refresh timed out (current_sas_token_put_time is not set)");
AzureIoTClient 30:20a85b733111 145 }
AzureIoTClient 30:20a85b733111 146 else
AzureIoTClient 30:20a85b733111 147 {
AzureIoTClient 30:20a85b733111 148 time_t current_time;
AzureIoTClient 30:20a85b733111 149
AzureIoTClient 30:20a85b733111 150 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 151 {
AzureIoTClient 30:20a85b733111 152 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 153 LogError("Failed verifying if SAS token refresh timed out (get_time failed)");
AzureIoTClient 30:20a85b733111 154 }
AzureIoTClient 30:20a85b733111 155 else if ((uint32_t)get_difftime(current_time, instance->current_sas_token_put_time) >= instance->sas_token_refresh_time_secs)
AzureIoTClient 30:20a85b733111 156 {
AzureIoTClient 30:20a85b733111 157 *is_timed_out = true;
AzureIoTClient 30:20a85b733111 158 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 159 }
AzureIoTClient 30:20a85b733111 160 else
AzureIoTClient 30:20a85b733111 161 {
AzureIoTClient 30:20a85b733111 162 *is_timed_out = false;
AzureIoTClient 30:20a85b733111 163 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 164 }
AzureIoTClient 30:20a85b733111 165 }
AzureIoTClient 30:20a85b733111 166
AzureIoTClient 30:20a85b733111 167 return result;
AzureIoTClient 30:20a85b733111 168 }
AzureIoTClient 30:20a85b733111 169
AzureIoTClient 30:20a85b733111 170 static STRING_HANDLE create_devices_path(STRING_HANDLE iothub_host_fqdn, STRING_HANDLE device_id)
AzureIoTClient 30:20a85b733111 171 {
AzureIoTClient 30:20a85b733111 172 STRING_HANDLE devices_path;
AzureIoTClient 30:20a85b733111 173
AzureIoTClient 30:20a85b733111 174 if ((devices_path = STRING_new()) == NULL)
AzureIoTClient 30:20a85b733111 175 {
AzureIoTClient 30:20a85b733111 176 LogError("Failed creating devices_path (STRING_new failed)");
AzureIoTClient 30:20a85b733111 177 }
AzureIoTClient 30:20a85b733111 178 else
AzureIoTClient 30:20a85b733111 179 {
AzureIoTClient 30:20a85b733111 180 const char* device_id_c_str = STRING_c_str(device_id);
AzureIoTClient 30:20a85b733111 181 const char* iothub_host_fqdn_c_str = STRING_c_str(iothub_host_fqdn);
AzureIoTClient 30:20a85b733111 182
AzureIoTClient 30:20a85b733111 183 if (STRING_sprintf(devices_path, IOTHUB_DEVICES_PATH_FMT, iothub_host_fqdn_c_str, device_id_c_str) != RESULT_OK)
AzureIoTClient 30:20a85b733111 184 {
AzureIoTClient 30:20a85b733111 185 STRING_delete(devices_path);
AzureIoTClient 30:20a85b733111 186 devices_path = NULL;
AzureIoTClient 30:20a85b733111 187 LogError("Failed creating devices_path (STRING_sprintf failed)");
AzureIoTClient 30:20a85b733111 188 }
AzureIoTClient 30:20a85b733111 189 }
AzureIoTClient 30:20a85b733111 190
AzureIoTClient 30:20a85b733111 191 return devices_path;
AzureIoTClient 30:20a85b733111 192 }
AzureIoTClient 30:20a85b733111 193
AzureIoTClient 30:20a85b733111 194
AzureIoTClient 30:20a85b733111 195 static bool are_device_keys_used_for_authentication(AUTHENTICATION_INSTANCE* instance)
AzureIoTClient 30:20a85b733111 196 {
AzureIoTClient 30:20a85b733111 197 return (instance->current_credential_in_use == DEVICE_PRIMARY_KEY || instance->current_credential_in_use == DEVICE_SECONDARY_KEY);
AzureIoTClient 30:20a85b733111 198 }
AzureIoTClient 30:20a85b733111 199
AzureIoTClient 30:20a85b733111 200 // @returns 0 there is one more device key to be attempted, !=0 otherwise.
AzureIoTClient 30:20a85b733111 201 static int mark_current_device_key_as_invalid(AUTHENTICATION_INSTANCE* instance)
AzureIoTClient 30:20a85b733111 202 {
AzureIoTClient 30:20a85b733111 203 int result;
AzureIoTClient 30:20a85b733111 204
AzureIoTClient 30:20a85b733111 205 if (instance->current_credential_in_use == DEVICE_PRIMARY_KEY)
AzureIoTClient 30:20a85b733111 206 {
AzureIoTClient 30:20a85b733111 207 if (instance->device_secondary_key != NULL)
AzureIoTClient 30:20a85b733111 208 {
AzureIoTClient 30:20a85b733111 209 instance->current_credential_in_use = DEVICE_SECONDARY_KEY;
AzureIoTClient 30:20a85b733111 210 LogError("Primary key of device '%s' was marked as invalid. Using secondary key now", STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 211 result = 0;
AzureIoTClient 30:20a85b733111 212 }
AzureIoTClient 30:20a85b733111 213 else
AzureIoTClient 30:20a85b733111 214 {
AzureIoTClient 30:20a85b733111 215 instance->current_credential_in_use = CREDENTIAL_TYPE_NONE;
AzureIoTClient 30:20a85b733111 216 LogError("Primary key of device '%s' was marked as invalid. No other device keys available", STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 217 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 218 }
AzureIoTClient 30:20a85b733111 219 }
AzureIoTClient 30:20a85b733111 220 else if (instance->current_credential_in_use == DEVICE_SECONDARY_KEY)
AzureIoTClient 30:20a85b733111 221 {
AzureIoTClient 30:20a85b733111 222 instance->current_credential_in_use = CREDENTIAL_TYPE_NONE;
AzureIoTClient 30:20a85b733111 223 LogError("Secondary key of device '%s' was marked as invalid. No other device keys available", STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 224 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 225 }
AzureIoTClient 30:20a85b733111 226 else
AzureIoTClient 30:20a85b733111 227 {
AzureIoTClient 30:20a85b733111 228 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 229 }
AzureIoTClient 30:20a85b733111 230
AzureIoTClient 30:20a85b733111 231 return result;
AzureIoTClient 30:20a85b733111 232 }
AzureIoTClient 30:20a85b733111 233
AzureIoTClient 30:20a85b733111 234 static STRING_HANDLE get_current_valid_device_key(AUTHENTICATION_INSTANCE* instance)
AzureIoTClient 30:20a85b733111 235 {
AzureIoTClient 30:20a85b733111 236 STRING_HANDLE device_key;
AzureIoTClient 30:20a85b733111 237
AzureIoTClient 30:20a85b733111 238 switch (instance->current_credential_in_use)
AzureIoTClient 30:20a85b733111 239 {
AzureIoTClient 30:20a85b733111 240 case DEVICE_PRIMARY_KEY:
AzureIoTClient 30:20a85b733111 241 device_key = instance->device_primary_key;
AzureIoTClient 30:20a85b733111 242 break;
AzureIoTClient 30:20a85b733111 243 case DEVICE_SECONDARY_KEY:
AzureIoTClient 30:20a85b733111 244 device_key = instance->device_secondary_key;
AzureIoTClient 30:20a85b733111 245 break;
AzureIoTClient 30:20a85b733111 246 default:
AzureIoTClient 30:20a85b733111 247 device_key = NULL;
AzureIoTClient 30:20a85b733111 248 break;
AzureIoTClient 30:20a85b733111 249 }
AzureIoTClient 30:20a85b733111 250
AzureIoTClient 30:20a85b733111 251 return device_key;
AzureIoTClient 30:20a85b733111 252 }
AzureIoTClient 30:20a85b733111 253
AzureIoTClient 30:20a85b733111 254 static void on_cbs_put_token_complete_callback(void* context, CBS_OPERATION_RESULT operation_result, unsigned int status_code, const char* status_description)
AzureIoTClient 30:20a85b733111 255 {
AzureIoTClient 30:20a85b733111 256 #ifdef NO_LOGGING
AzureIoTClient 30:20a85b733111 257 UNUSED(status_code);
AzureIoTClient 30:20a85b733111 258 UNUSED(status_description);
AzureIoTClient 30:20a85b733111 259 #endif
AzureIoTClient 30:20a85b733111 260 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 261
AzureIoTClient 30:20a85b733111 262 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_095: [`instance->is_sas_token_refresh_in_progress` and `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 263 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 30:20a85b733111 264
AzureIoTClient 30:20a85b733111 265 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_091: [If `result` is CBS_OPERATION_RESULT_OK `instance->state` shall be set to AUTHENTICATION_STATE_STARTED and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 266 if (operation_result == CBS_OPERATION_RESULT_OK)
AzureIoTClient 30:20a85b733111 267 {
AzureIoTClient 30:20a85b733111 268 update_state(instance, AUTHENTICATION_STATE_STARTED);
AzureIoTClient 30:20a85b733111 269 }
AzureIoTClient 30:20a85b733111 270 else
AzureIoTClient 30:20a85b733111 271 {
AzureIoTClient 30:20a85b733111 272 LogError("CBS reported status code %u, error: '%s' for put-token operation for device '%s'", status_code, status_description, STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 273
AzureIoTClient 30:20a85b733111 274 if (mark_current_device_key_as_invalid(instance) != 0)
AzureIoTClient 30:20a85b733111 275 {
AzureIoTClient 30:20a85b733111 276 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_092: [If `result` is not CBS_OPERATION_RESULT_OK `instance->state` shall be set to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 277 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 278
AzureIoTClient 30:20a85b733111 279 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_094: [If `result` is not CBS_OPERATION_RESULT_OK and `instance->is_sas_token_refresh_in_progress` is TRUE, `instance->on_error_callback`shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_FAILED]
AzureIoTClient 30:20a85b733111 280 if (instance->is_sas_token_refresh_in_progress)
AzureIoTClient 30:20a85b733111 281 {
AzureIoTClient 30:20a85b733111 282 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_FAILED);
AzureIoTClient 30:20a85b733111 283 }
AzureIoTClient 30:20a85b733111 284 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_093: [If `result` is not CBS_OPERATION_RESULT_OK and `instance->is_sas_token_refresh_in_progress` is FALSE, `instance->on_error_callback`shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 30:20a85b733111 285 else
AzureIoTClient 30:20a85b733111 286 {
AzureIoTClient 30:20a85b733111 287 notify_error(instance, AUTHENTICATION_ERROR_AUTH_FAILED);
AzureIoTClient 30:20a85b733111 288 }
AzureIoTClient 30:20a85b733111 289 }
AzureIoTClient 30:20a85b733111 290 }
AzureIoTClient 30:20a85b733111 291
AzureIoTClient 30:20a85b733111 292 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 30:20a85b733111 293 }
AzureIoTClient 30:20a85b733111 294
AzureIoTClient 30:20a85b733111 295 static int put_SAS_token_to_cbs(AUTHENTICATION_INSTANCE* instance, STRING_HANDLE cbs_audience, STRING_HANDLE sas_token)
AzureIoTClient 30:20a85b733111 296 {
AzureIoTClient 30:20a85b733111 297 int result;
AzureIoTClient 30:20a85b733111 298
AzureIoTClient 30:20a85b733111 299 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_043: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 30:20a85b733111 300 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_057: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 30:20a85b733111 301 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_075: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 30:20a85b733111 302 instance->is_cbs_put_token_in_progress = true;
AzureIoTClient 30:20a85b733111 303
AzureIoTClient 30:20a85b733111 304 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_046: [The SAS token provided shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 30:20a85b733111 305 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_058: [The SAS token shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 30:20a85b733111 306 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_076: [The SAS token shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 30:20a85b733111 307 const char* sas_token_c_str = STRING_c_str(sas_token);
AzureIoTClient 30:20a85b733111 308 const char* cbs_audience_c_str = STRING_c_str(cbs_audience);
AzureIoTClient 31:adadaef857c1 309 if (cbs_put_token_async(instance->cbs_handle, SAS_TOKEN_TYPE, cbs_audience_c_str, sas_token_c_str, on_cbs_put_token_complete_callback, instance) != RESULT_OK)
AzureIoTClient 30:20a85b733111 310 {
AzureIoTClient 30:20a85b733111 311 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_048: [If cbs_put_token() failed, authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to FALSE, destroy `devices_path` and return]
AzureIoTClient 30:20a85b733111 312 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_060: [If cbs_put_token() fails, `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 313 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_078: [If cbs_put_token() fails, `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 314 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 30:20a85b733111 315 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 316 LogError("Failed putting SAS token to CBS for device '%s' (cbs_put_token failed)", STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 317 }
AzureIoTClient 30:20a85b733111 318 else
AzureIoTClient 30:20a85b733111 319 {
AzureIoTClient 30:20a85b733111 320 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_047: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with current time]
AzureIoTClient 30:20a85b733111 321 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_059: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with current time]
AzureIoTClient 30:20a85b733111 322 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_077: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with the current time]
AzureIoTClient 30:20a85b733111 323 time_t current_time;
AzureIoTClient 30:20a85b733111 324
AzureIoTClient 30:20a85b733111 325 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 326 {
AzureIoTClient 30:20a85b733111 327 LogError("Failed setting current_sas_token_put_time for device '%s' (get_time() failed)", STRING_c_str(instance->device_id));
AzureIoTClient 30:20a85b733111 328 }
AzureIoTClient 30:20a85b733111 329
AzureIoTClient 30:20a85b733111 330 instance->current_sas_token_put_time = current_time; // If it failed, fear not. `current_sas_token_put_time` shall be checked for INDEFINITE_TIME wherever it is used.
AzureIoTClient 30:20a85b733111 331
AzureIoTClient 30:20a85b733111 332 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 333 }
AzureIoTClient 30:20a85b733111 334
AzureIoTClient 30:20a85b733111 335 return result;
AzureIoTClient 30:20a85b733111 336 }
AzureIoTClient 30:20a85b733111 337
AzureIoTClient 30:20a85b733111 338 static int create_and_put_SAS_token_to_cbs(AUTHENTICATION_INSTANCE* instance, STRING_HANDLE device_key)
AzureIoTClient 30:20a85b733111 339 {
AzureIoTClient 30:20a85b733111 340 int result;
AzureIoTClient 30:20a85b733111 341 double seconds_since_epoch;
AzureIoTClient 30:20a85b733111 342
AzureIoTClient 30:20a85b733111 343 if (get_seconds_since_epoch(&seconds_since_epoch) != RESULT_OK)
AzureIoTClient 30:20a85b733111 344 {
AzureIoTClient 30:20a85b733111 345 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 346 LogError("Failed creating a SAS token (get_seconds_since_epoch() failed)");
AzureIoTClient 30:20a85b733111 347 }
AzureIoTClient 30:20a85b733111 348 else
AzureIoTClient 30:20a85b733111 349 {
AzureIoTClient 30:20a85b733111 350 STRING_HANDLE devices_path = NULL;
AzureIoTClient 30:20a85b733111 351 STRING_HANDLE sasTokenKeyName = NULL;
AzureIoTClient 30:20a85b733111 352 STRING_HANDLE sas_token = NULL;
AzureIoTClient 30:20a85b733111 353
AzureIoTClient 30:20a85b733111 354 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_052: [The SAS token expiration time shall be calculated adding `instance->sas_token_lifetime_secs` to the current number of seconds since epoch time UTC]
AzureIoTClient 30:20a85b733111 355 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_070: [The SAS token expiration time shall be calculated adding `instance->sas_token_lifetime_secs` to the current number of seconds since epoch time UTC]
AzureIoTClient 30:20a85b733111 356 size_t sas_token_expiration_time_secs = (size_t)seconds_since_epoch + instance->sas_token_lifetime_secs;
AzureIoTClient 30:20a85b733111 357
AzureIoTClient 30:20a85b733111 358 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_053: [A STRING_HANDLE, referred to as `devices_path`, shall be created from the following parts: iothub_host_fqdn + "/devices/" + device_id]
AzureIoTClient 30:20a85b733111 359 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_071: [A STRING_HANDLE, referred to as `devices_path`, shall be created from the following parts: iothub_host_fqdn + "/devices/" + device_id]
AzureIoTClient 30:20a85b733111 360 if ((devices_path = create_devices_path(instance->iothub_host_fqdn, instance->device_id)) == NULL)
AzureIoTClient 30:20a85b733111 361 {
AzureIoTClient 30:20a85b733111 362 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_054: [If `devices_path` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 363 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_072: [If `devices_path` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 364 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 365 LogError("Failed creating a SAS token (create_devices_path() failed)");
AzureIoTClient 30:20a85b733111 366 }
AzureIoTClient 30:20a85b733111 367 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_115: [An empty STRING_HANDLE, referred to as `sasTokenKeyName`, shall be created using STRING_new()]
AzureIoTClient 30:20a85b733111 368 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_117: [An empty STRING_HANDLE, referred to as `sasTokenKeyName`, shall be created using STRING_new()]
AzureIoTClient 30:20a85b733111 369 else if ((sasTokenKeyName = STRING_new()) == NULL)
AzureIoTClient 30:20a85b733111 370 {
AzureIoTClient 30:20a85b733111 371 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_116: [If `sasTokenKeyName` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 372 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_118: [If `sasTokenKeyName` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 373 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 374 LogError("Failed creating a SAS token (STRING_new() failed)");
AzureIoTClient 30:20a85b733111 375 }
AzureIoTClient 30:20a85b733111 376 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_055: [The SAS token shall be created using SASToken_Create(), passing the selected device key, `device_path`, `sasTokenKeyName` and expiration time as arguments]
AzureIoTClient 30:20a85b733111 377 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_073: [The SAS token shall be created using SASToken_Create(), passing the selected device key, device_path, sasTokenKeyName and expiration time as arguments]
AzureIoTClient 30:20a85b733111 378 else if ((sas_token = SASToken_Create(device_key, devices_path, sasTokenKeyName, (size_t)sas_token_expiration_time_secs)) == NULL)
AzureIoTClient 30:20a85b733111 379 {
AzureIoTClient 30:20a85b733111 380 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_056: [If SASToken_Create() fails, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 381 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_074: [If SASToken_Create() fails, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 382 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 383 LogError("Failed creating a SAS token (SASToken_Create() failed)");
AzureIoTClient 30:20a85b733111 384 }
AzureIoTClient 30:20a85b733111 385 else if (put_SAS_token_to_cbs(instance, devices_path, sas_token) != RESULT_OK)
AzureIoTClient 30:20a85b733111 386 {
AzureIoTClient 30:20a85b733111 387 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 388 LogError("Failed putting SAS token to CBS");
AzureIoTClient 30:20a85b733111 389 }
AzureIoTClient 30:20a85b733111 390 else
AzureIoTClient 30:20a85b733111 391 {
AzureIoTClient 30:20a85b733111 392 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 393 }
AzureIoTClient 30:20a85b733111 394
AzureIoTClient 30:20a85b733111 395 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_081: [authentication_do_work() shall free the memory it allocated for `devices_path`, `sasTokenKeyName` and SAS token]
AzureIoTClient 30:20a85b733111 396 if (devices_path != NULL)
AzureIoTClient 30:20a85b733111 397 STRING_delete(devices_path);
AzureIoTClient 30:20a85b733111 398 if (sasTokenKeyName != NULL)
AzureIoTClient 30:20a85b733111 399 STRING_delete(sasTokenKeyName);
AzureIoTClient 30:20a85b733111 400 if (sas_token != NULL)
AzureIoTClient 30:20a85b733111 401 STRING_delete(sas_token);
AzureIoTClient 30:20a85b733111 402 }
AzureIoTClient 30:20a85b733111 403
AzureIoTClient 30:20a85b733111 404 return result;
AzureIoTClient 30:20a85b733111 405 }
AzureIoTClient 30:20a85b733111 406
AzureIoTClient 30:20a85b733111 407
AzureIoTClient 30:20a85b733111 408 // ---------- Set/Retrieve Options Helpers ----------//
AzureIoTClient 30:20a85b733111 409
AzureIoTClient 30:20a85b733111 410 static void* authentication_clone_option(const char* name, const void* value)
AzureIoTClient 30:20a85b733111 411 {
AzureIoTClient 30:20a85b733111 412 void* result;
AzureIoTClient 30:20a85b733111 413
AzureIoTClient 30:20a85b733111 414 if (name == NULL)
AzureIoTClient 30:20a85b733111 415 {
AzureIoTClient 30:20a85b733111 416 LogError("Failed to clone authentication option (name is NULL)");
AzureIoTClient 30:20a85b733111 417 result = NULL;
AzureIoTClient 30:20a85b733111 418 }
AzureIoTClient 30:20a85b733111 419 else if (value == NULL)
AzureIoTClient 30:20a85b733111 420 {
AzureIoTClient 30:20a85b733111 421 LogError("Failed to clone authentication option (value is NULL)");
AzureIoTClient 30:20a85b733111 422 result = NULL;
AzureIoTClient 30:20a85b733111 423 }
AzureIoTClient 30:20a85b733111 424 else
AzureIoTClient 30:20a85b733111 425 {
AzureIoTClient 30:20a85b733111 426 if (strcmp(AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, name) == 0 ||
AzureIoTClient 30:20a85b733111 427 strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, name) == 0 ||
AzureIoTClient 30:20a85b733111 428 strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, name) == 0 ||
AzureIoTClient 30:20a85b733111 429 strcmp(AUTHENTICATION_OPTION_SAVED_OPTIONS, name) == 0)
AzureIoTClient 30:20a85b733111 430 {
AzureIoTClient 30:20a85b733111 431 result = (void*)value;
AzureIoTClient 30:20a85b733111 432 }
AzureIoTClient 30:20a85b733111 433 else
AzureIoTClient 30:20a85b733111 434 {
AzureIoTClient 30:20a85b733111 435 LogError("Failed to clone authentication option (option with name '%s' is not suppported)", name);
AzureIoTClient 30:20a85b733111 436 result = NULL;
AzureIoTClient 30:20a85b733111 437 }
AzureIoTClient 30:20a85b733111 438 }
AzureIoTClient 30:20a85b733111 439
AzureIoTClient 30:20a85b733111 440 return result;
AzureIoTClient 30:20a85b733111 441 }
AzureIoTClient 30:20a85b733111 442
AzureIoTClient 30:20a85b733111 443 static void authentication_destroy_option(const char* name, const void* value)
AzureIoTClient 30:20a85b733111 444 {
AzureIoTClient 30:20a85b733111 445 if (name == NULL)
AzureIoTClient 30:20a85b733111 446 {
AzureIoTClient 30:20a85b733111 447 LogError("Failed to destroy authentication option (name is NULL)");
AzureIoTClient 30:20a85b733111 448 }
AzureIoTClient 30:20a85b733111 449 else if (value == NULL)
AzureIoTClient 30:20a85b733111 450 {
AzureIoTClient 30:20a85b733111 451 LogError("Failed to destroy authentication option (value is NULL)");
AzureIoTClient 30:20a85b733111 452 }
AzureIoTClient 30:20a85b733111 453 else
AzureIoTClient 30:20a85b733111 454 {
AzureIoTClient 30:20a85b733111 455 if (strcmp(name, AUTHENTICATION_OPTION_SAVED_OPTIONS) == 0)
AzureIoTClient 30:20a85b733111 456 {
AzureIoTClient 30:20a85b733111 457 OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
AzureIoTClient 30:20a85b733111 458 }
AzureIoTClient 30:20a85b733111 459 }
AzureIoTClient 30:20a85b733111 460 }
AzureIoTClient 30:20a85b733111 461
AzureIoTClient 30:20a85b733111 462
AzureIoTClient 30:20a85b733111 463 // Public APIs:
AzureIoTClient 30:20a85b733111 464
AzureIoTClient 30:20a85b733111 465 int authentication_start(AUTHENTICATION_HANDLE authentication_handle, const CBS_HANDLE cbs_handle)
AzureIoTClient 30:20a85b733111 466 {
AzureIoTClient 30:20a85b733111 467 int result;
AzureIoTClient 30:20a85b733111 468
AzureIoTClient 30:20a85b733111 469 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_025: [If authentication_handle is NULL, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 30:20a85b733111 470 if (authentication_handle == NULL)
AzureIoTClient 30:20a85b733111 471 {
AzureIoTClient 30:20a85b733111 472 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 473 LogError("authentication_start failed (authentication_handle is NULL)");
AzureIoTClient 30:20a85b733111 474 }
AzureIoTClient 30:20a85b733111 475 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_026: [If `cbs_handle` is NULL, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 30:20a85b733111 476 else if (cbs_handle == NULL)
AzureIoTClient 30:20a85b733111 477 {
AzureIoTClient 30:20a85b733111 478 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 479 LogError("authentication_start failed (cbs_handle is NULL)");
AzureIoTClient 30:20a85b733111 480 }
AzureIoTClient 30:20a85b733111 481 else
AzureIoTClient 30:20a85b733111 482 {
AzureIoTClient 30:20a85b733111 483 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 484
AzureIoTClient 30:20a85b733111 485 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_027: [If authenticate state has been started already, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 30:20a85b733111 486 if (instance->state != AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 30:20a85b733111 487 {
AzureIoTClient 30:20a85b733111 488 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 489 LogError("authentication_start failed (messenger has already been started; current state: %d)", instance->state);
AzureIoTClient 30:20a85b733111 490 }
AzureIoTClient 30:20a85b733111 491 else
AzureIoTClient 30:20a85b733111 492 {
AzureIoTClient 30:20a85b733111 493 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_028: [authentication_start() shall save `cbs_handle` on `instance->cbs_handle`]
AzureIoTClient 30:20a85b733111 494 instance->cbs_handle = cbs_handle;
AzureIoTClient 30:20a85b733111 495
AzureIoTClient 30:20a85b733111 496 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_029: [If no failures occur, `instance->state` shall be set to AUTHENTICATION_STATE_STARTING and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 497 update_state(instance, AUTHENTICATION_STATE_STARTING);
AzureIoTClient 30:20a85b733111 498
AzureIoTClient 30:20a85b733111 499 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_030: [If no failures occur, authentication_start() shall return 0]
AzureIoTClient 30:20a85b733111 500 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 501 }
AzureIoTClient 30:20a85b733111 502 }
AzureIoTClient 30:20a85b733111 503
AzureIoTClient 30:20a85b733111 504 return result;
AzureIoTClient 30:20a85b733111 505 }
AzureIoTClient 30:20a85b733111 506
AzureIoTClient 30:20a85b733111 507 int authentication_stop(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 508 {
AzureIoTClient 30:20a85b733111 509 int result;
AzureIoTClient 30:20a85b733111 510
AzureIoTClient 30:20a85b733111 511 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_031: [If `authentication_handle` is NULL, authentication_stop() shall fail and return __FAILURE__]
AzureIoTClient 30:20a85b733111 512 if (authentication_handle == NULL)
AzureIoTClient 30:20a85b733111 513 {
AzureIoTClient 30:20a85b733111 514 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 515 LogError("authentication_stop failed (authentication_handle is NULL)");
AzureIoTClient 30:20a85b733111 516 }
AzureIoTClient 30:20a85b733111 517 else
AzureIoTClient 30:20a85b733111 518 {
AzureIoTClient 30:20a85b733111 519 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 520
AzureIoTClient 30:20a85b733111 521 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_032: [If `instance->state` is AUTHENTICATION_STATE_STOPPED, authentication_stop() shall fail and return __FAILURE__]
AzureIoTClient 30:20a85b733111 522 if (instance->state == AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 30:20a85b733111 523 {
AzureIoTClient 30:20a85b733111 524 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 525 LogError("authentication_stop failed (messenger is already stopped)");
AzureIoTClient 30:20a85b733111 526 }
AzureIoTClient 30:20a85b733111 527 else
AzureIoTClient 30:20a85b733111 528 {
AzureIoTClient 30:20a85b733111 529 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_033: [`instance->cbs_handle` shall be set to NULL]
AzureIoTClient 30:20a85b733111 530 instance->cbs_handle = NULL;
AzureIoTClient 30:20a85b733111 531
AzureIoTClient 30:20a85b733111 532 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_034: [`instance->state` shall be set to AUTHENTICATION_STATE_STOPPED and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 533 update_state(instance, AUTHENTICATION_STATE_STOPPED);
AzureIoTClient 30:20a85b733111 534
AzureIoTClient 30:20a85b733111 535 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_035: [authentication_stop() shall return success code 0]
AzureIoTClient 30:20a85b733111 536 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 537 }
AzureIoTClient 30:20a85b733111 538 }
AzureIoTClient 30:20a85b733111 539
AzureIoTClient 30:20a85b733111 540 return result;
AzureIoTClient 30:20a85b733111 541 }
AzureIoTClient 30:20a85b733111 542
AzureIoTClient 30:20a85b733111 543 void authentication_destroy(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 544 {
AzureIoTClient 30:20a85b733111 545 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_106: [If authentication_handle is NULL, authentication_destroy() shall return]
AzureIoTClient 30:20a85b733111 546 if (authentication_handle == NULL)
AzureIoTClient 30:20a85b733111 547 {
AzureIoTClient 30:20a85b733111 548 LogError("authentication_destroy failed (authentication_handle is NULL)");
AzureIoTClient 30:20a85b733111 549 }
AzureIoTClient 30:20a85b733111 550 else
AzureIoTClient 30:20a85b733111 551 {
AzureIoTClient 30:20a85b733111 552 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 553
AzureIoTClient 30:20a85b733111 554 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_107: [If `instance->state` is AUTHENTICATION_STATE_STARTING or AUTHENTICATION_STATE_STARTED, authentication_stop() shall be invoked and its result ignored]
AzureIoTClient 30:20a85b733111 555 if (instance->state != AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 30:20a85b733111 556 {
AzureIoTClient 30:20a85b733111 557 (void)authentication_stop(authentication_handle);
AzureIoTClient 30:20a85b733111 558 }
AzureIoTClient 30:20a85b733111 559
AzureIoTClient 30:20a85b733111 560 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_108: [authentication_destroy() shall destroy `instance->device_id` using STRING_delete()]
AzureIoTClient 30:20a85b733111 561 if (instance->device_id != NULL)
AzureIoTClient 30:20a85b733111 562 STRING_delete(instance->device_id);
AzureIoTClient 30:20a85b733111 563
AzureIoTClient 30:20a85b733111 564 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_109: [authentication_destroy() shall destroy `instance->device_sas_token` using STRING_delete()]
AzureIoTClient 30:20a85b733111 565 if (instance->device_sas_token != NULL)
AzureIoTClient 30:20a85b733111 566 STRING_delete(instance->device_sas_token);
AzureIoTClient 30:20a85b733111 567
AzureIoTClient 30:20a85b733111 568 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_110: [authentication_destroy() shall destroy `instance->device_primary_key` using STRING_delete()]
AzureIoTClient 30:20a85b733111 569 if (instance->device_primary_key != NULL)
AzureIoTClient 30:20a85b733111 570 STRING_delete(instance->device_primary_key);
AzureIoTClient 30:20a85b733111 571
AzureIoTClient 30:20a85b733111 572 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_111: [authentication_destroy() shall destroy `instance->device_secondary_key` using STRING_delete()]
AzureIoTClient 30:20a85b733111 573 if (instance->device_secondary_key != NULL)
AzureIoTClient 30:20a85b733111 574 STRING_delete(instance->device_secondary_key);
AzureIoTClient 30:20a85b733111 575
AzureIoTClient 30:20a85b733111 576 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_112: [authentication_destroy() shall destroy `instance->iothub_host_fqdn` using STRING_delete()]
AzureIoTClient 30:20a85b733111 577 if (instance->iothub_host_fqdn != NULL)
AzureIoTClient 30:20a85b733111 578 STRING_delete(instance->iothub_host_fqdn);
AzureIoTClient 30:20a85b733111 579
AzureIoTClient 30:20a85b733111 580 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_113: [authentication_destroy() shall destroy `instance` using free()]
AzureIoTClient 30:20a85b733111 581 free(instance);
AzureIoTClient 30:20a85b733111 582 }
AzureIoTClient 30:20a85b733111 583 }
AzureIoTClient 30:20a85b733111 584
AzureIoTClient 30:20a85b733111 585 AUTHENTICATION_HANDLE authentication_create(const AUTHENTICATION_CONFIG* config)
AzureIoTClient 30:20a85b733111 586 {
AzureIoTClient 30:20a85b733111 587 AUTHENTICATION_HANDLE result;
AzureIoTClient 30:20a85b733111 588
AzureIoTClient 30:20a85b733111 589 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_001: [If parameter `config` or `config->device_id` are NULL, authentication_create() shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 590 if (config == NULL)
AzureIoTClient 30:20a85b733111 591 {
AzureIoTClient 30:20a85b733111 592 result = NULL;
AzureIoTClient 30:20a85b733111 593 LogError("authentication_create failed (config is NULL)");
AzureIoTClient 30:20a85b733111 594 }
AzureIoTClient 30:20a85b733111 595 else if (config->device_id == NULL)
AzureIoTClient 30:20a85b733111 596 {
AzureIoTClient 30:20a85b733111 597 result = NULL;
AzureIoTClient 30:20a85b733111 598 LogError("authentication_create failed (config->device_id is NULL)");
AzureIoTClient 30:20a85b733111 599 }
AzureIoTClient 30:20a85b733111 600 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_002: [If device keys and SAS token are NULL, authentication_create() shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 601 else if (config->device_sas_token == NULL && config->device_primary_key == NULL)
AzureIoTClient 30:20a85b733111 602 {
AzureIoTClient 30:20a85b733111 603 result = NULL;
AzureIoTClient 30:20a85b733111 604 LogError("authentication_create failed (either config->device_sas_token or config->device_primary_key must be provided; config->device_secondary_key is optional)");
AzureIoTClient 30:20a85b733111 605 }
AzureIoTClient 30:20a85b733111 606 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_003: [If device keys and SAS token are both provided, authentication_create() shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 607 else if (config->device_sas_token != NULL && (config->device_primary_key != NULL || config->device_secondary_key != NULL))
AzureIoTClient 30:20a85b733111 608 {
AzureIoTClient 30:20a85b733111 609 result = NULL;
AzureIoTClient 30:20a85b733111 610 LogError("authentication_create failed (both config->device_sas_token and device device keys were provided; must provide only one)");
AzureIoTClient 30:20a85b733111 611 }
AzureIoTClient 30:20a85b733111 612 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_004: [If `config->iothub_host_fqdn` is NULL, authentication_create() shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 613 else if (config->iothub_host_fqdn == NULL)
AzureIoTClient 30:20a85b733111 614 {
AzureIoTClient 30:20a85b733111 615 result = NULL;
AzureIoTClient 30:20a85b733111 616 LogError("authentication_create failed (config->iothub_host_fqdn is NULL)");
AzureIoTClient 30:20a85b733111 617 }
AzureIoTClient 30:20a85b733111 618 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_005: [If `config->on_state_changed_callback` is NULL, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 619 else if (config->on_state_changed_callback == NULL)
AzureIoTClient 30:20a85b733111 620 {
AzureIoTClient 30:20a85b733111 621 result = NULL;
AzureIoTClient 30:20a85b733111 622 LogError("authentication_create failed (config->on_state_changed_callback is NULL)");
AzureIoTClient 30:20a85b733111 623 }
AzureIoTClient 30:20a85b733111 624 else
AzureIoTClient 30:20a85b733111 625 {
AzureIoTClient 30:20a85b733111 626 AUTHENTICATION_INSTANCE* instance;
AzureIoTClient 30:20a85b733111 627
AzureIoTClient 30:20a85b733111 628 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_006: [authentication_create() shall allocate memory for a new authenticate state structure AUTHENTICATION_INSTANCE.]
AzureIoTClient 30:20a85b733111 629 if ((instance = (AUTHENTICATION_INSTANCE*)malloc(sizeof(AUTHENTICATION_INSTANCE))) == NULL)
AzureIoTClient 30:20a85b733111 630 {
AzureIoTClient 30:20a85b733111 631 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_007: [If malloc() fails, authentication_create() shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 632 result = NULL;
AzureIoTClient 30:20a85b733111 633 LogError("authentication_create failed (malloc failed)");
AzureIoTClient 30:20a85b733111 634 }
AzureIoTClient 30:20a85b733111 635 else
AzureIoTClient 30:20a85b733111 636 {
AzureIoTClient 30:20a85b733111 637 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_123: [authentication_create() shall initialize all fields of `instance` with 0 using memset().]
AzureIoTClient 30:20a85b733111 638 memset(instance, 0, sizeof(AUTHENTICATION_INSTANCE));
AzureIoTClient 30:20a85b733111 639
AzureIoTClient 30:20a85b733111 640 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_008: [authentication_create() shall save a copy of `config->device_id` into the `instance->device_id`]
AzureIoTClient 30:20a85b733111 641 if ((instance->device_id = STRING_construct(config->device_id)) == NULL)
AzureIoTClient 30:20a85b733111 642 {
AzureIoTClient 30:20a85b733111 643 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_009: [If STRING_construct() fails, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 644 result = NULL;
AzureIoTClient 30:20a85b733111 645 LogError("authentication_create failed (config->device_id could not be copied; STRING_construct failed)");
AzureIoTClient 30:20a85b733111 646 }
AzureIoTClient 30:20a85b733111 647 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_010: [If `device_config->device_sas_token` is not NULL, authentication_create() shall save a copy into the `instance->device_sas_token`]
AzureIoTClient 30:20a85b733111 648 else if (config->device_sas_token != NULL && (instance->device_sas_token = STRING_construct(config->device_sas_token)) == NULL)
AzureIoTClient 30:20a85b733111 649 {
AzureIoTClient 30:20a85b733111 650 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_011: [If STRING_construct() fails, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 651 result = NULL;
AzureIoTClient 30:20a85b733111 652 LogError("authentication_create failed (config->device_sas_token could not be copied; STRING_construct failed)");
AzureIoTClient 30:20a85b733111 653 }
AzureIoTClient 30:20a85b733111 654 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_012: [If provided, authentication_create() shall save a copy of `config->device_primary_key` into the `instance->device_primary_key`]
AzureIoTClient 30:20a85b733111 655 else if (config->device_primary_key != NULL && (instance->device_primary_key = STRING_construct(config->device_primary_key)) == NULL)
AzureIoTClient 30:20a85b733111 656 {
AzureIoTClient 30:20a85b733111 657 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_013: [If STRING_construct() fails to copy `config->device_primary_key`, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 658 result = NULL;
AzureIoTClient 30:20a85b733111 659 LogError("authentication_create failed (config->device_primary_key could not be copied; STRING_construct failed)");
AzureIoTClient 30:20a85b733111 660 }
AzureIoTClient 30:20a85b733111 661 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_014: [If provided, authentication_create() shall save a copy of `config->device_secondary_key` into `instance->device_secondary_key`]
AzureIoTClient 30:20a85b733111 662 else if (config->device_secondary_key != NULL && (instance->device_secondary_key = STRING_construct(config->device_secondary_key)) == NULL)
AzureIoTClient 30:20a85b733111 663 {
AzureIoTClient 30:20a85b733111 664 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_015: [If STRING_construct() fails to copy `config->device_secondary_key`, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 665 result = NULL;
AzureIoTClient 30:20a85b733111 666 LogError("authentication_create failed (config->device_secondary_key could not be copied; STRING_construct failed)");
AzureIoTClient 30:20a85b733111 667 }
AzureIoTClient 30:20a85b733111 668 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_016: [If provided, authentication_create() shall save a copy of `config->iothub_host_fqdn` into `instance->iothub_host_fqdn`]
AzureIoTClient 30:20a85b733111 669 else if ((instance->iothub_host_fqdn = STRING_construct(config->iothub_host_fqdn)) == NULL)
AzureIoTClient 30:20a85b733111 670 {
AzureIoTClient 30:20a85b733111 671 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_017: [If STRING_clone() fails to copy `config->iothub_host_fqdn`, authentication_create() shall fail and return NULL]
AzureIoTClient 30:20a85b733111 672 result = NULL;
AzureIoTClient 30:20a85b733111 673 LogError("authentication_create failed (config->iothub_host_fqdn could not be copied; STRING_construct failed)");
AzureIoTClient 30:20a85b733111 674 }
AzureIoTClient 30:20a85b733111 675 else
AzureIoTClient 30:20a85b733111 676 {
AzureIoTClient 30:20a85b733111 677 instance->state = AUTHENTICATION_STATE_STOPPED;
AzureIoTClient 30:20a85b733111 678
AzureIoTClient 30:20a85b733111 679 if (instance->device_sas_token != NULL)
AzureIoTClient 30:20a85b733111 680 {
AzureIoTClient 30:20a85b733111 681 instance->current_credential_in_use = USER_PROVIDED_SAS_TOKEN;
AzureIoTClient 30:20a85b733111 682 }
AzureIoTClient 30:20a85b733111 683 else
AzureIoTClient 30:20a85b733111 684 {
AzureIoTClient 30:20a85b733111 685 instance->current_credential_in_use = DEVICE_PRIMARY_KEY;
AzureIoTClient 30:20a85b733111 686 }
AzureIoTClient 30:20a85b733111 687
AzureIoTClient 30:20a85b733111 688 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_018: [authentication_create() shall save `config->on_state_changed_callback` and `config->on_state_changed_callback_context` into `instance->on_state_changed_callback` and `instance->on_state_changed_callback_context`.]
AzureIoTClient 30:20a85b733111 689 instance->on_state_changed_callback = config->on_state_changed_callback;
AzureIoTClient 30:20a85b733111 690 instance->on_state_changed_callback_context = config->on_state_changed_callback_context;
AzureIoTClient 30:20a85b733111 691
AzureIoTClient 30:20a85b733111 692 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_019: [authentication_create() shall save `config->on_error_callback` and `config->on_error_callback_context` into `instance->on_error_callback` and `instance->on_error_callback_context`.]
AzureIoTClient 30:20a85b733111 693 instance->on_error_callback = config->on_error_callback;
AzureIoTClient 30:20a85b733111 694 instance->on_error_callback_context = config->on_error_callback_context;
AzureIoTClient 30:20a85b733111 695
AzureIoTClient 30:20a85b733111 696 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_021: [authentication_create() shall set `instance->cbs_request_timeout_secs` with the default value of UINT32_MAX]
AzureIoTClient 30:20a85b733111 697 instance->cbs_request_timeout_secs = DEFAULT_CBS_REQUEST_TIMEOUT_SECS;
AzureIoTClient 30:20a85b733111 698 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_022: [authentication_create() shall set `instance->sas_token_lifetime_secs` with the default value of one hour]
AzureIoTClient 30:20a85b733111 699 instance->sas_token_lifetime_secs = DEFAULT_SAS_TOKEN_LIFETIME_SECS;
AzureIoTClient 30:20a85b733111 700 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_023: [authentication_create() shall set `instance->sas_token_refresh_time_secs` with the default value of 30 minutes]
AzureIoTClient 30:20a85b733111 701 instance->sas_token_refresh_time_secs = DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS;
AzureIoTClient 30:20a85b733111 702
AzureIoTClient 30:20a85b733111 703 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_024: [If no failure occurs, authentication_create() shall return a reference to the AUTHENTICATION_INSTANCE handle]
AzureIoTClient 30:20a85b733111 704 result = (AUTHENTICATION_HANDLE)instance;
AzureIoTClient 30:20a85b733111 705 }
AzureIoTClient 30:20a85b733111 706
AzureIoTClient 30:20a85b733111 707 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_020: [If any failure occurs, authentication_create() shall free any memory it allocated previously]
AzureIoTClient 30:20a85b733111 708 if (result == NULL)
AzureIoTClient 30:20a85b733111 709 {
AzureIoTClient 30:20a85b733111 710 authentication_destroy((AUTHENTICATION_HANDLE)instance);
AzureIoTClient 30:20a85b733111 711 }
AzureIoTClient 30:20a85b733111 712 }
AzureIoTClient 30:20a85b733111 713 }
AzureIoTClient 30:20a85b733111 714
AzureIoTClient 30:20a85b733111 715 return result;
AzureIoTClient 30:20a85b733111 716 }
AzureIoTClient 30:20a85b733111 717
AzureIoTClient 30:20a85b733111 718 void authentication_do_work(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 719 {
AzureIoTClient 30:20a85b733111 720 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_036: [If authentication_handle is NULL, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 721 if (authentication_handle == NULL)
AzureIoTClient 30:20a85b733111 722 {
AzureIoTClient 30:20a85b733111 723 LogError("authentication_do_work failed (authentication_handle is NULL)");
AzureIoTClient 30:20a85b733111 724 }
AzureIoTClient 30:20a85b733111 725 else
AzureIoTClient 30:20a85b733111 726 {
AzureIoTClient 30:20a85b733111 727 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 728
AzureIoTClient 30:20a85b733111 729 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_038: [If `instance->is_cbs_put_token_in_progress` is TRUE, authentication_do_work() shall only verify the authentication timeout]
AzureIoTClient 30:20a85b733111 730 if (instance->is_cbs_put_token_in_progress)
AzureIoTClient 30:20a85b733111 731 {
AzureIoTClient 30:20a85b733111 732 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_084: [If no timeout has occurred, authentication_do_work() shall return]
AzureIoTClient 30:20a85b733111 733
AzureIoTClient 30:20a85b733111 734 bool is_timed_out;
AzureIoTClient 30:20a85b733111 735 if (verify_cbs_put_token_timeout(instance, &is_timed_out) == RESULT_OK && is_timed_out)
AzureIoTClient 30:20a85b733111 736 {
AzureIoTClient 30:20a85b733111 737 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_085: [`instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 738 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 30:20a85b733111 739
AzureIoTClient 30:20a85b733111 740 if (mark_current_device_key_as_invalid(instance))
AzureIoTClient 30:20a85b733111 741 {
AzureIoTClient 30:20a85b733111 742 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_086: [`instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 743 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 744
AzureIoTClient 30:20a85b733111 745 if (instance->is_sas_token_refresh_in_progress)
AzureIoTClient 30:20a85b733111 746 {
AzureIoTClient 30:20a85b733111 747 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_087: [If `instance->is_sas_token_refresh_in_progress` is TRUE, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_TIMEOUT]
AzureIoTClient 30:20a85b733111 748 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_TIMEOUT);
AzureIoTClient 30:20a85b733111 749 }
AzureIoTClient 30:20a85b733111 750 else
AzureIoTClient 30:20a85b733111 751 {
AzureIoTClient 30:20a85b733111 752 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_088: [If `instance->is_sas_token_refresh_in_progress` is FALSE, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_TIMEOUT]
AzureIoTClient 30:20a85b733111 753 notify_error(instance, AUTHENTICATION_ERROR_AUTH_TIMEOUT);
AzureIoTClient 30:20a85b733111 754 }
AzureIoTClient 30:20a85b733111 755 }
AzureIoTClient 30:20a85b733111 756
AzureIoTClient 30:20a85b733111 757 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_089: [`instance->is_sas_token_refresh_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 758 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 30:20a85b733111 759 }
AzureIoTClient 30:20a85b733111 760 }
AzureIoTClient 30:20a85b733111 761 else if (instance->state == AUTHENTICATION_STATE_STARTED)
AzureIoTClient 30:20a85b733111 762 {
AzureIoTClient 30:20a85b733111 763 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_040: [If `instance->state` is AUTHENTICATION_STATE_STARTED and user-provided SAS token was used, authentication_do_work() shall return]
AzureIoTClient 30:20a85b733111 764 if (are_device_keys_used_for_authentication(instance))
AzureIoTClient 30:20a85b733111 765 {
AzureIoTClient 30:20a85b733111 766 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_039: [If `instance->state` is AUTHENTICATION_STATE_STARTED and device keys were used, authentication_do_work() shall only verify the SAS token refresh time]
AzureIoTClient 30:20a85b733111 767 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_065: [The SAS token shall be refreshed if the current time minus `instance->current_sas_token_put_time` equals or exceeds `instance->sas_token_refresh_time_secs`]
AzureIoTClient 30:20a85b733111 768 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_066: [If SAS token does not need to be refreshed, authentication_do_work() shall return]
AzureIoTClient 30:20a85b733111 769 bool is_timed_out;
AzureIoTClient 30:20a85b733111 770 if (verify_sas_token_refresh_timeout(instance, &is_timed_out) == RESULT_OK && is_timed_out)
AzureIoTClient 30:20a85b733111 771 {
AzureIoTClient 30:20a85b733111 772 STRING_HANDLE device_key;
AzureIoTClient 30:20a85b733111 773
AzureIoTClient 30:20a85b733111 774 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_119: [authentication_do_work() shall set `instance->is_sas_token_refresh_in_progress` to TRUE]
AzureIoTClient 30:20a85b733111 775 instance->is_sas_token_refresh_in_progress = true;
AzureIoTClient 30:20a85b733111 776
AzureIoTClient 30:20a85b733111 777 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_067: [authentication_do_work() shall create a SAS token using `instance->device_primary_key`, unless it has failed previously]
AzureIoTClient 30:20a85b733111 778 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_069: [If using `instance->device_primary_key` has failed previously, a SAS token shall be created using `instance->device_secondary_key`]
AzureIoTClient 30:20a85b733111 779 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_068: [If using `instance->device_primary_key` has failed previously and `instance->device_secondary_key` is not provided, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 780 while ((device_key = get_current_valid_device_key(instance)) != NULL)
AzureIoTClient 30:20a85b733111 781 {
AzureIoTClient 30:20a85b733111 782 if (create_and_put_SAS_token_to_cbs(instance, device_key) == RESULT_OK)
AzureIoTClient 30:20a85b733111 783 {
AzureIoTClient 30:20a85b733111 784 break;
AzureIoTClient 30:20a85b733111 785 }
AzureIoTClient 30:20a85b733111 786 else
AzureIoTClient 30:20a85b733111 787 {
AzureIoTClient 30:20a85b733111 788 LogError("Failed refreshing SAS token (%d)", instance->current_credential_in_use);
AzureIoTClient 30:20a85b733111 789 (void)mark_current_device_key_as_invalid(instance);
AzureIoTClient 30:20a85b733111 790 }
AzureIoTClient 30:20a85b733111 791 }
AzureIoTClient 30:20a85b733111 792
AzureIoTClient 30:20a85b733111 793 if (!instance->is_cbs_put_token_in_progress)
AzureIoTClient 30:20a85b733111 794 {
AzureIoTClient 30:20a85b733111 795 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_120: [If cbs_put_token() fails, `instance->is_sas_token_refresh_in_progress` shall be set to FALSE]
AzureIoTClient 30:20a85b733111 796 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 30:20a85b733111 797
AzureIoTClient 30:20a85b733111 798 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_079: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 799 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 800
AzureIoTClient 30:20a85b733111 801 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_080: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_FAILED]
AzureIoTClient 30:20a85b733111 802 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_FAILED);
AzureIoTClient 30:20a85b733111 803 }
AzureIoTClient 30:20a85b733111 804 }
AzureIoTClient 30:20a85b733111 805 }
AzureIoTClient 30:20a85b733111 806 }
AzureIoTClient 30:20a85b733111 807 else if (instance->state == AUTHENTICATION_STATE_STARTING)
AzureIoTClient 30:20a85b733111 808 {
AzureIoTClient 30:20a85b733111 809 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_041: [If `instance->device_sas_token` is provided, authentication_do_work() shall put it to CBS]
AzureIoTClient 30:20a85b733111 810 if (instance->device_sas_token != NULL)
AzureIoTClient 30:20a85b733111 811 {
AzureIoTClient 30:20a85b733111 812 STRING_HANDLE devices_path;
AzureIoTClient 30:20a85b733111 813
AzureIoTClient 30:20a85b733111 814 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_044: [A STRING_HANDLE, referred to as `devices_path`, shall be created from the following parts: iothub_host_fqdn + "/devices/" + device_id]
AzureIoTClient 30:20a85b733111 815 if ((devices_path = create_devices_path(instance->iothub_host_fqdn, instance->device_id)) == NULL)
AzureIoTClient 30:20a85b733111 816 {
AzureIoTClient 30:20a85b733111 817 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_045: [If `devices_path` failed to be created, authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to FALSE and return]
AzureIoTClient 30:20a85b733111 818 LogError("Failed authenticating using SAS token (create_devices_path() failed)");
AzureIoTClient 30:20a85b733111 819 }
AzureIoTClient 30:20a85b733111 820 else if (put_SAS_token_to_cbs(instance, devices_path, instance->device_sas_token) != RESULT_OK)
AzureIoTClient 30:20a85b733111 821 {
AzureIoTClient 30:20a85b733111 822 LogError("Failed authenticating using SAS token (put_SAS_token_to_cbs() failed)");
AzureIoTClient 30:20a85b733111 823 }
AzureIoTClient 30:20a85b733111 824
AzureIoTClient 30:20a85b733111 825 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_063: [authentication_do_work() shall free the memory it allocated for `devices_path`, `sasTokenKeyName` and SAS token]
AzureIoTClient 30:20a85b733111 826 STRING_delete(devices_path);
AzureIoTClient 30:20a85b733111 827 }
AzureIoTClient 30:20a85b733111 828 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_042: [Otherwise, authentication_do_work() shall use device keys for CBS authentication]
AzureIoTClient 30:20a85b733111 829 else
AzureIoTClient 30:20a85b733111 830 {
AzureIoTClient 30:20a85b733111 831 STRING_HANDLE device_key;
AzureIoTClient 30:20a85b733111 832
AzureIoTClient 30:20a85b733111 833 while ((device_key = get_current_valid_device_key(instance)) != NULL)
AzureIoTClient 30:20a85b733111 834 {
AzureIoTClient 30:20a85b733111 835 if (create_and_put_SAS_token_to_cbs(instance, device_key) == RESULT_OK)
AzureIoTClient 30:20a85b733111 836 {
AzureIoTClient 30:20a85b733111 837 break;
AzureIoTClient 30:20a85b733111 838 }
AzureIoTClient 30:20a85b733111 839 else
AzureIoTClient 30:20a85b733111 840 {
AzureIoTClient 30:20a85b733111 841 LogError("Failed authenticating device '%s' using device keys (%d)", STRING_c_str(instance->device_id), instance->current_credential_in_use);
AzureIoTClient 30:20a85b733111 842 (void)mark_current_device_key_as_invalid(instance);
AzureIoTClient 30:20a85b733111 843 }
AzureIoTClient 30:20a85b733111 844 }
AzureIoTClient 30:20a85b733111 845 }
AzureIoTClient 30:20a85b733111 846
AzureIoTClient 30:20a85b733111 847 if (!instance->is_cbs_put_token_in_progress)
AzureIoTClient 30:20a85b733111 848 {
AzureIoTClient 30:20a85b733111 849 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_061: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 850 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_121: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 30:20a85b733111 851 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 852
AzureIoTClient 30:20a85b733111 853 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_062: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 30:20a85b733111 854 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_122: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 30:20a85b733111 855 notify_error(instance, AUTHENTICATION_ERROR_AUTH_FAILED);
AzureIoTClient 30:20a85b733111 856 }
AzureIoTClient 30:20a85b733111 857 }
AzureIoTClient 30:20a85b733111 858 else
AzureIoTClient 30:20a85b733111 859 {
AzureIoTClient 30:20a85b733111 860 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_037: [If `instance->state` is not AUTHENTICATION_STATE_STARTING or AUTHENTICATION_STATE_STARTED, authentication_do_work() shall fail and return]
AzureIoTClient 30:20a85b733111 861 // Nothing to be done.
AzureIoTClient 30:20a85b733111 862 }
AzureIoTClient 30:20a85b733111 863 }
AzureIoTClient 30:20a85b733111 864 }
AzureIoTClient 30:20a85b733111 865
AzureIoTClient 30:20a85b733111 866 int authentication_set_option(AUTHENTICATION_HANDLE authentication_handle, const char* name, void* value)
AzureIoTClient 30:20a85b733111 867 {
AzureIoTClient 30:20a85b733111 868 int result;
AzureIoTClient 30:20a85b733111 869
AzureIoTClient 30:20a85b733111 870 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_097: [If `authentication_handle` or `name` or `value` is NULL, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 30:20a85b733111 871 if (authentication_handle == NULL || name == NULL || value == NULL)
AzureIoTClient 30:20a85b733111 872 {
AzureIoTClient 30:20a85b733111 873 LogError("authentication_set_option failed (one of the followin are NULL: authentication_handle=%p, name=%p, value=%p)",
AzureIoTClient 30:20a85b733111 874 authentication_handle, name, value);
AzureIoTClient 30:20a85b733111 875 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 876 }
AzureIoTClient 30:20a85b733111 877 else
AzureIoTClient 30:20a85b733111 878 {
AzureIoTClient 30:20a85b733111 879 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 880
AzureIoTClient 30:20a85b733111 881 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_098: [If name matches AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, `value` shall be saved on `instance->cbs_request_timeout_secs`]
AzureIoTClient 30:20a85b733111 882 if (strcmp(AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, name) == 0)
AzureIoTClient 30:20a85b733111 883 {
AzureIoTClient 30:20a85b733111 884 instance->cbs_request_timeout_secs = *((size_t*)value);
AzureIoTClient 30:20a85b733111 885 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 886 }
AzureIoTClient 30:20a85b733111 887 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_124: [If name matches AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, `value` shall be saved on `instance->sas_token_refresh_time_secs`]
AzureIoTClient 30:20a85b733111 888 else if (strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, name) == 0)
AzureIoTClient 30:20a85b733111 889 {
AzureIoTClient 30:20a85b733111 890 instance->sas_token_refresh_time_secs = *((size_t*)value);
AzureIoTClient 30:20a85b733111 891 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 892 }
AzureIoTClient 30:20a85b733111 893 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_125: [If name matches AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, `value` shall be saved on `instance->sas_token_lifetime_secs`]
AzureIoTClient 30:20a85b733111 894 else if (strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, name) == 0)
AzureIoTClient 30:20a85b733111 895 {
AzureIoTClient 30:20a85b733111 896 instance->sas_token_lifetime_secs = *((size_t*)value);
AzureIoTClient 30:20a85b733111 897 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 898 }
AzureIoTClient 30:20a85b733111 899 else if (strcmp(AUTHENTICATION_OPTION_SAVED_OPTIONS, name) == 0)
AzureIoTClient 30:20a85b733111 900 {
AzureIoTClient 30:20a85b733111 901 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_098: [If name matches AUTHENTICATION_OPTION_SAVED_OPTIONS, `value` shall be applied using OptionHandler_FeedOptions]
AzureIoTClient 30:20a85b733111 902 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, authentication_handle) != OPTIONHANDLER_OK)
AzureIoTClient 30:20a85b733111 903 {
AzureIoTClient 30:20a85b733111 904 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_126: [If OptionHandler_FeedOptions fails, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 30:20a85b733111 905 LogError("authentication_set_option failed (OptionHandler_FeedOptions failed)");
AzureIoTClient 30:20a85b733111 906 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 907 }
AzureIoTClient 30:20a85b733111 908 else
AzureIoTClient 30:20a85b733111 909 {
AzureIoTClient 30:20a85b733111 910 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 911 }
AzureIoTClient 30:20a85b733111 912 }
AzureIoTClient 30:20a85b733111 913 else
AzureIoTClient 30:20a85b733111 914 {
AzureIoTClient 30:20a85b733111 915 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_128: [If name does not match any supported option, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 30:20a85b733111 916 LogError("authentication_set_option failed (option with name '%s' is not suppported)", name);
AzureIoTClient 30:20a85b733111 917 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 918 }
AzureIoTClient 30:20a85b733111 919 }
AzureIoTClient 30:20a85b733111 920
AzureIoTClient 30:20a85b733111 921 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_099: [If no errors occur, authentication_set_option shall return 0]
AzureIoTClient 30:20a85b733111 922 return result;
AzureIoTClient 30:20a85b733111 923 }
AzureIoTClient 30:20a85b733111 924
AzureIoTClient 30:20a85b733111 925 OPTIONHANDLER_HANDLE authentication_retrieve_options(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 926 {
AzureIoTClient 30:20a85b733111 927 OPTIONHANDLER_HANDLE result;
AzureIoTClient 30:20a85b733111 928
AzureIoTClient 30:20a85b733111 929 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_100: [If `authentication_handle` is NULL, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 30:20a85b733111 930 if (authentication_handle == NULL)
AzureIoTClient 30:20a85b733111 931 {
AzureIoTClient 30:20a85b733111 932 LogError("Failed to retrieve options from authentication instance (authentication_handle is NULL)");
AzureIoTClient 30:20a85b733111 933 result = NULL;
AzureIoTClient 30:20a85b733111 934 }
AzureIoTClient 30:20a85b733111 935 else
AzureIoTClient 30:20a85b733111 936 {
AzureIoTClient 30:20a85b733111 937 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_101: [An OPTIONHANDLER_HANDLE instance shall be created using OptionHandler_Create]
AzureIoTClient 30:20a85b733111 938 OPTIONHANDLER_HANDLE options = OptionHandler_Create(authentication_clone_option, authentication_destroy_option, (pfSetOption)authentication_set_option);
AzureIoTClient 30:20a85b733111 939
AzureIoTClient 30:20a85b733111 940 if (options == NULL)
AzureIoTClient 30:20a85b733111 941 {
AzureIoTClient 30:20a85b733111 942 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_102: [If an OPTIONHANDLER_HANDLE instance fails to be created, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 30:20a85b733111 943 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed)");
AzureIoTClient 30:20a85b733111 944 result = NULL;
AzureIoTClient 30:20a85b733111 945 }
AzureIoTClient 30:20a85b733111 946 else
AzureIoTClient 30:20a85b733111 947 {
AzureIoTClient 30:20a85b733111 948 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 949
AzureIoTClient 30:20a85b733111 950 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_103: [Each option of `instance` shall be added to the OPTIONHANDLER_HANDLE instance using OptionHandler_AddOption]
AzureIoTClient 30:20a85b733111 951 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_104: [If OptionHandler_AddOption fails, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 30:20a85b733111 952 if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, (void*)&instance->cbs_request_timeout_secs) != OPTIONHANDLER_OK)
AzureIoTClient 30:20a85b733111 953 {
AzureIoTClient 30:20a85b733111 954 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS);
AzureIoTClient 30:20a85b733111 955 result = NULL;
AzureIoTClient 30:20a85b733111 956 }
AzureIoTClient 30:20a85b733111 957 else if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, (void*)&instance->sas_token_refresh_time_secs) != OPTIONHANDLER_OK)
AzureIoTClient 30:20a85b733111 958 {
AzureIoTClient 30:20a85b733111 959 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS);
AzureIoTClient 30:20a85b733111 960 result = NULL;
AzureIoTClient 30:20a85b733111 961 }
AzureIoTClient 30:20a85b733111 962 else if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, (void*)&instance->sas_token_lifetime_secs) != OPTIONHANDLER_OK)
AzureIoTClient 30:20a85b733111 963 {
AzureIoTClient 30:20a85b733111 964 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS);
AzureIoTClient 30:20a85b733111 965 result = NULL;
AzureIoTClient 30:20a85b733111 966 }
AzureIoTClient 30:20a85b733111 967 else
AzureIoTClient 30:20a85b733111 968 {
AzureIoTClient 30:20a85b733111 969 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_127: [If no failures occur, authentication_retrieve_options shall return the OPTIONHANDLER_HANDLE instance]
AzureIoTClient 30:20a85b733111 970 result = options;
AzureIoTClient 30:20a85b733111 971 }
AzureIoTClient 30:20a85b733111 972
AzureIoTClient 30:20a85b733111 973 if (result == NULL)
AzureIoTClient 30:20a85b733111 974 {
AzureIoTClient 30:20a85b733111 975 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_105: [If authentication_retrieve_options fails, any allocated memory shall be freed]
AzureIoTClient 30:20a85b733111 976 OptionHandler_Destroy(options);
AzureIoTClient 30:20a85b733111 977 }
AzureIoTClient 30:20a85b733111 978 }
AzureIoTClient 30:20a85b733111 979 }
AzureIoTClient 30:20a85b733111 980
AzureIoTClient 30:20a85b733111 981 return result;
AzureIoTClient 30:20a85b733111 982 }