1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "simple_auth_context.h"
16
17 #include <set>
18 #include <vector>
19
20 #include "auth_common.h"
21 #include "iam_check.h"
22 #include "iam_logger.h"
23 #include "iam_para2str.h"
24 #include "publish_event_adapter.h"
25 #include "resource_node.h"
26 #include "resource_node_utils.h"
27 #include "schedule_node.h"
28 #include "schedule_node_callback.h"
29 #include "thread_handler_manager.h"
30 #include "user_idm_database.h"
31
32 #define LOG_TAG "USER_AUTH_SA"
33 namespace OHOS {
34 namespace UserIam {
35 namespace UserAuth {
GetPropertyTemplateIds(Authentication::AuthResultInfo & resultInfo)36 std::optional<std::vector<uint64_t>> SimpleAuthContext::GetPropertyTemplateIds(
37 Authentication::AuthResultInfo &resultInfo)
38 {
39 IAM_LOGI("start");
40 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleList_.size() == 1, std::nullopt);
41 auto scheduleNode = scheduleList_[0];
42 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleNode != nullptr, std::nullopt);
43 if (scheduleNode->GetAuthType() != PRIVATE_PIN) {
44 return scheduleNode->GetTemplateIdList();
45 }
46
47 std::vector<uint64_t> templateIds;
48 std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
49 int32_t ret = UserIdmDatabase::Instance().GetCredentialInfo(resultInfo.userId, scheduleNode->GetAuthType(),
50 credInfos);
51 if (ret != SUCCESS) {
52 IAM_LOGE("get credential fail, ret:%{public}d, userId:%{public}d, authType:%{public}d", ret,
53 resultInfo.userId, scheduleNode->GetAuthType());
54 return std::nullopt;
55 }
56
57 for (auto &iter : credInfos) {
58 if (scheduleNode->GetAuthIntent() == QUESTION_AUTH) {
59 if (iter->GetAuthSubType() == PIN_QUESTION) {
60 templateIds.push_back(iter->GetTemplateId());
61 break;
62 }
63 } else {
64 if (iter->GetAuthSubType() != PIN_QUESTION) {
65 templateIds.push_back(iter->GetTemplateId());
66 break;
67 }
68 }
69 }
70
71 return templateIds;
72 }
73
GetPropertyForAuthResult(Authentication::AuthResultInfo & resultInfo)74 ResultCode SimpleAuthContext::GetPropertyForAuthResult(Authentication::AuthResultInfo &resultInfo)
75 {
76 IAM_LOGD("start");
77 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleList_.size() == 1, GENERAL_ERROR);
78 auto scheduleNode = scheduleList_[0];
79 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleNode != nullptr, GENERAL_ERROR);
80 if (scheduleNode->GetAuthType() == PIN) {
81 resultInfo.nextFailLockoutDuration = FIRST_LOCKOUT_DURATION_OF_PIN;
82 } else {
83 resultInfo.nextFailLockoutDuration = FIRST_LOCKOUT_DURATION_EXCEPT_PIN;
84 }
85 if (resultInfo.result != FAIL && resultInfo.result != LOCKED) {
86 IAM_LOGI("no need GetPropertyFromExecutor, nextLockDuration:%{public}d", resultInfo.nextFailLockoutDuration);
87 return SUCCESS;
88 }
89
90 auto resourceNode = scheduleNode->GetVerifyExecutor().lock();
91 IF_FALSE_LOGE_AND_RETURN_VAL(resourceNode != nullptr, GENERAL_ERROR);
92 auto optionalTemplateIdList = GetPropertyTemplateIds(resultInfo);
93 IF_FALSE_LOGE_AND_RETURN_VAL(optionalTemplateIdList.has_value(), GENERAL_ERROR);
94 std::vector<uint64_t> templateIdList = optionalTemplateIdList.value();
95 std::vector<uint32_t> keys = { Attributes::ATTR_FREEZING_TIME, Attributes::ATTR_REMAIN_TIMES};
96 if (scheduleNode->GetAuthType() == PIN) {
97 keys.push_back(Attributes::ATTR_NEXT_FAIL_LOCKOUT_DURATION);
98 }
99 Attributes attr;
100 attr.SetUint32ArrayValue(Attributes::ATTR_KEY_LIST, keys);
101 attr.SetUint32Value(Attributes::ATTR_PROPERTY_MODE, PROPERTY_MODE_GET);
102 attr.SetUint64ArrayValue(Attributes::ATTR_TEMPLATE_ID_LIST, templateIdList);
103
104 Attributes values;
105 int32_t ret = resourceNode->GetProperty(attr, values);
106 IF_FALSE_LOGE_AND_RETURN_VAL(ret == SUCCESS, GENERAL_ERROR);
107
108 if (scheduleNode->GetAuthType() == PIN) {
109 bool getNextDurationRet = values.GetInt32Value(Attributes::ATTR_NEXT_FAIL_LOCKOUT_DURATION,
110 resultInfo.nextFailLockoutDuration);
111 IF_FALSE_LOGE_AND_RETURN_VAL(getNextDurationRet == true, GENERAL_ERROR);
112 }
113 bool getFreezingTimeRet = values.GetInt32Value(Attributes::ATTR_FREEZING_TIME, resultInfo.freezingTime);
114 IF_FALSE_LOGE_AND_RETURN_VAL(getFreezingTimeRet == true, GENERAL_ERROR);
115 bool getRemainTimesRet = values.GetInt32Value(Attributes::ATTR_REMAIN_TIMES, resultInfo.remainTimes);
116 IF_FALSE_LOGE_AND_RETURN_VAL(getRemainTimesRet == true, GENERAL_ERROR);
117
118 IAM_LOGI("success, nextFailLockoutDuration:%{public}d, freezingTime:%{public}d, remainTime:%{public}d",
119 resultInfo.nextFailLockoutDuration, resultInfo.freezingTime, resultInfo.remainTimes);
120 return SUCCESS;
121 }
122
SimpleAuthContext(uint64_t contextId,std::shared_ptr<Authentication> auth,std::shared_ptr<ContextCallback> callback,bool needSubscribeAppState)123 SimpleAuthContext::SimpleAuthContext(uint64_t contextId, std::shared_ptr<Authentication> auth,
124 std::shared_ptr<ContextCallback> callback, bool needSubscribeAppState)
125 : BaseContext("SimpleAuth", contextId, callback, needSubscribeAppState),
126 auth_(auth)
127 {
128 }
129
SimpleAuthContext(const std::string & type,uint64_t contextId,std::shared_ptr<Authentication> auth,std::shared_ptr<ContextCallback> callback)130 SimpleAuthContext::SimpleAuthContext(const std::string &type, uint64_t contextId, std::shared_ptr<Authentication> auth,
131 std::shared_ptr<ContextCallback> callback)
132 : BaseContext(type, contextId, callback, true),
133 auth_(auth)
134 {
135 }
136
GetContextType() const137 ContextType SimpleAuthContext::GetContextType() const
138 {
139 return CONTEXT_SIMPLE_AUTH;
140 }
141
GetTokenId() const142 uint32_t SimpleAuthContext::GetTokenId() const
143 {
144 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, 0);
145 return auth_->GetAccessTokenId();
146 }
147
GetUserId() const148 int32_t SimpleAuthContext::GetUserId() const
149 {
150 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, INVALID_USER_ID);
151 return auth_->GetUserId();
152 }
153
GetAuthType() const154 int32_t SimpleAuthContext::GetAuthType() const
155 {
156 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, INVALID_AUTH_TYPE);
157 return auth_->GetAuthType();
158 }
159
GetCallerName() const160 std::string SimpleAuthContext::GetCallerName() const
161 {
162 IF_FALSE_LOGE_AND_RETURN_VAL(callback_ != nullptr, "");
163 return callback_->GetCallerName();
164 }
165
OnStart()166 bool SimpleAuthContext::OnStart()
167 {
168 IAM_LOGD("%{public}s start", GetDescription());
169 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, false);
170 bool startRet = auth_->Start(scheduleList_, shared_from_this());
171 if (!startRet) {
172 IAM_LOGE("%{public}s auth start fail", GetDescription());
173 SetLatestError(auth_->GetLatestError());
174 return startRet;
175 }
176 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleList_.size() == 1, false);
177 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleList_[0] != nullptr, false);
178 bool startScheduleRet = scheduleList_[0]->StartSchedule();
179 IF_FALSE_LOGE_AND_RETURN_VAL(startScheduleRet, false);
180 IAM_LOGI("%{public}s Schedule:%{public}s Type:%{public}d success", GetDescription(),
181 GET_MASKED_STRING(scheduleList_[0]->GetScheduleId()).c_str(), scheduleList_[0]->GetAuthType());
182 return true;
183 }
184
OnResult(int32_t resultCode,const std::shared_ptr<Attributes> & scheduleResultAttr)185 void SimpleAuthContext::OnResult(int32_t resultCode, const std::shared_ptr<Attributes> &scheduleResultAttr)
186 {
187 IAM_LOGI("%{public}s receive result code %{public}d", GetDescription(), resultCode);
188 Authentication::AuthResultInfo resultInfo = {};
189 bool updateRet = UpdateScheduleResult(scheduleResultAttr, resultInfo);
190 IAM_LOGI("update result %{public}d, resultInfo result %{public}d", updateRet, resultInfo.result);
191 if (!updateRet) {
192 IAM_LOGE("%{public}s UpdateScheduleResult fail", GetDescription());
193 if (resultCode == SUCCESS) {
194 resultCode = GetLatestError();
195 }
196 resultInfo.result = resultCode;
197 } else if (resultCode != resultInfo.result) {
198 resultInfo.result = (resultInfo.result == SUCCESS ? resultCode : resultInfo.result);
199 }
200 if (GetPropertyForAuthResult(resultInfo) != SUCCESS) {
201 IAM_LOGE("GetPropertyForAuthResult failed");
202 }
203
204 if (resultInfo.result == SUCCESS && GetAuthType() == PIN) {
205 PublishEventAdapter::GetInstance().CachePinUpdateParam(resultInfo.reEnrollFlag);
206 }
207 SendAuthExecutorMsg();
208 InvokeResultCallback(resultInfo);
209 IAM_LOGI("%{public}s on result %{public}d finish", GetDescription(), resultInfo.result);
210 }
211
OnStop()212 bool SimpleAuthContext::OnStop()
213 {
214 IAM_LOGI("%{public}s start", GetDescription());
215 if (scheduleList_.size() == 1 && scheduleList_[0] != nullptr) {
216 scheduleList_[0]->StopSchedule();
217 }
218
219 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, false);
220 bool cancelRet = auth_->Cancel();
221 if (!cancelRet) {
222 IAM_LOGE("%{public}s auth stop fail", GetDescription());
223 SetLatestError(auth_->GetLatestError());
224 return cancelRet;
225 }
226 return true;
227 }
228
SendAuthExecutorMsg()229 void SimpleAuthContext::SendAuthExecutorMsg()
230 {
231 IAM_LOGI("begin");
232 IF_FALSE_LOGE_AND_RETURN(auth_ != nullptr);
233 auto authExecutorMsgs = auth_->GetAuthExecutorMsgs();
234 auto &threadManager = ThreadHandlerManager::GetInstance();
235
236 for (uint32_t msgIndex = 0; msgIndex < authExecutorMsgs.size(); msgIndex++) {
237 auto authExecutorMsg = authExecutorMsgs[msgIndex];
238 std::string threadName = std::to_string(GetContextId()) + "_msg_" + std::to_string(msgIndex);
239 if (!threadManager.CreateThreadHandler(threadName)) {
240 IAM_LOGE("Failed to create thread handler for executor message");
241 continue;
242 }
243
244 threadManager.PostTask(threadName, [authExecutorMsg, threadName]() {
245 ResourceNodeUtils::SendMsgToExecutor(
246 authExecutorMsg.executorIndex, authExecutorMsg.commandId, authExecutorMsg.msg);
247 });
248
249 threadManager.DestroyThreadHandler(threadName);
250 }
251 IAM_LOGI("end");
252 }
253
UpdateScheduleResult(const std::shared_ptr<Attributes> & scheduleResultAttr,Authentication::AuthResultInfo & resultInfo)254 bool SimpleAuthContext::UpdateScheduleResult(const std::shared_ptr<Attributes> &scheduleResultAttr,
255 Authentication::AuthResultInfo &resultInfo)
256 {
257 IF_FALSE_LOGE_AND_RETURN_VAL(auth_ != nullptr, false);
258 IF_FALSE_LOGE_AND_RETURN_VAL(scheduleResultAttr != nullptr, false);
259 std::vector<uint8_t> scheduleResult;
260 bool getResultCodeRet = scheduleResultAttr->GetUint8ArrayValue(Attributes::ATTR_RESULT, scheduleResult);
261 IF_FALSE_LOGE_AND_RETURN_VAL(getResultCodeRet == true, false);
262 bool updateRet = auth_->Update(scheduleResult, resultInfo);
263 if (!updateRet) {
264 IAM_LOGE("%{public}s auth update fail", GetDescription());
265 SetLatestError(auth_->GetLatestError());
266 return updateRet;
267 }
268 return true;
269 }
270
SetCredentialDigest(const Authentication::AuthResultInfo & resultInfo,Attributes & finalResult) const271 bool SimpleAuthContext::SetCredentialDigest(const Authentication::AuthResultInfo &resultInfo,
272 Attributes &finalResult) const
273 {
274 uint64_t credentialDigest = resultInfo.credentialDigest;
275 if (resultInfo.sdkVersion < INNER_API_VERSION_10000) {
276 credentialDigest = resultInfo.credentialDigest & UINT16_MAX;
277 }
278 bool setCredentialDigestRet = finalResult.SetUint64Value(Attributes::ATTR_CREDENTIAL_DIGEST,
279 credentialDigest);
280 IF_FALSE_LOGE_AND_RETURN_VAL(setCredentialDigestRet == true, false);
281 bool setCredentialCountRet = finalResult.SetUint16Value(Attributes::ATTR_CREDENTIAL_COUNT,
282 resultInfo.credentialCount);
283 IF_FALSE_LOGE_AND_RETURN_VAL(setCredentialCountRet == true, false);
284
285 return true;
286 }
287
InvokeResultCallback(const Authentication::AuthResultInfo & resultInfo) const288 void SimpleAuthContext::InvokeResultCallback(const Authentication::AuthResultInfo &resultInfo) const
289 {
290 IAM_LOGD("%{public}s start", GetDescription());
291 IF_FALSE_LOGE_AND_RETURN(callback_ != nullptr);
292 Attributes finalResult;
293 bool setResultCodeRet = finalResult.SetInt32Value(Attributes::ATTR_RESULT_CODE, resultInfo.result);
294 IF_FALSE_LOGE_AND_RETURN(setResultCodeRet == true);
295 bool setNextDurationRet = finalResult.SetInt32Value(Attributes::ATTR_NEXT_FAIL_LOCKOUT_DURATION,
296 resultInfo.nextFailLockoutDuration);
297 IF_FALSE_LOGE_AND_RETURN(setNextDurationRet == true);
298 if (resultInfo.result == FAIL || resultInfo.result == LOCKED || resultInfo.result == SUCCESS) {
299 bool setFreezingTimeRet = finalResult.SetInt32Value(Attributes::ATTR_FREEZING_TIME, resultInfo.freezingTime);
300 IF_FALSE_LOGE_AND_RETURN(setFreezingTimeRet == true);
301 bool setRemainTimesRet = finalResult.SetInt32Value(Attributes::ATTR_REMAIN_TIMES, resultInfo.remainTimes);
302 IF_FALSE_LOGE_AND_RETURN(setRemainTimesRet == true);
303 }
304 if ((resultInfo.result == SUCCESS || resultInfo.token.size() != 0) && resultInfo.sdkVersion > API_VERSION_9) {
305 bool credentialDigest = SetCredentialDigest(resultInfo, finalResult);
306 IF_FALSE_LOGE_AND_RETURN(credentialDigest == true);
307 }
308 if (resultInfo.result == SUCCESS) {
309 bool setUserIdRet = finalResult.SetInt32Value(Attributes::ATTR_USER_ID, resultInfo.userId);
310 IF_FALSE_LOGE_AND_RETURN(setUserIdRet == true);
311 bool setCredentialIdRet = finalResult.SetUint64Value(Attributes::ATTR_CREDENTIAL_ID, resultInfo.credentialId);
312 IF_FALSE_LOGE_AND_RETURN(setCredentialIdRet == true);
313 IAM_LOGI("matched userId: %{public}d, credentialId: %{public}s.", resultInfo.userId,
314 GET_MASKED_STRING(resultInfo.credentialId).c_str());
315 bool setExpiredRet = finalResult.SetInt64Value(Attributes::ATTR_PIN_EXPIRED_INFO, resultInfo.pinExpiredInfo);
316 IF_FALSE_LOGE_AND_RETURN(setExpiredRet == true);
317 }
318 if (resultInfo.token.size() != 0) {
319 IAM_LOGI("result token size: %{public}zu.", resultInfo.token.size());
320 bool setSignatureResult = finalResult.SetUint8ArrayValue(Attributes::ATTR_SIGNATURE, resultInfo.token);
321 IF_FALSE_LOGE_AND_RETURN(setSignatureResult == true);
322 }
323 if (resultInfo.rootSecret.size() != 0) {
324 bool setRootSecret = finalResult.SetUint8ArrayValue(Attributes::ATTR_ROOT_SECRET, resultInfo.rootSecret);
325 IF_FALSE_LOGE_AND_RETURN(setRootSecret == true);
326 }
327 if (resultInfo.remoteAuthResultMsg.size() != 0) {
328 bool setRemoteAuthResultMsg = finalResult.SetUint8ArrayValue(Attributes::ATTR_SIGNED_AUTH_RESULT,
329 resultInfo.remoteAuthResultMsg);
330 IF_FALSE_LOGE_AND_RETURN(setRemoteAuthResultMsg == true);
331 }
332 bool setReEnrollFlagRet = finalResult.SetBoolValue(Attributes::ATTR_RE_ENROLL_FLAG, resultInfo.reEnrollFlag);
333 IF_FALSE_LOGE_AND_RETURN(setReEnrollFlagRet == true);
334
335 callback_->SetTraceAuthFinishReason("SimpleAuthContext InvokeResultCallback");
336 callback_->OnResult(resultInfo.result, finalResult);
337 IAM_LOGI("%{public}s invoke result callback success, result %{public}d", GetDescription(), resultInfo.result);
338 }
339 } // namespace UserAuth
340 } // namespace UserIam
341 } // namespace OHOS
342