1 /*
2 * Copyright (c) 2023 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 "widget_context.h"
16
17 #include <algorithm>
18
19 #include "context_helper.h"
20 #include "context_pool.h"
21 #include "iam_check.h"
22 #include "iam_logger.h"
23 #include "iam_ptr.h"
24 #include "iam_time.h"
25 #include "schedule_node.h"
26 #include "schedule_node_callback.h"
27 #include "widget_schedule_node_impl.h"
28 #include "widget_context_callback_impl.h"
29 #include "widget_client.h"
30 #include "widget_json.h"
31 #include "bool_wrapper.h"
32 #include "double_wrapper.h"
33 #include "int_wrapper.h"
34 #include "string_wrapper.h"
35 #include "want_params_wrapper.h"
36 #include "ability_connection.h"
37 #include "ability_connect_callback.h"
38 #include "refbase.h"
39 #include "hisysevent_adapter.h"
40
41 #define LOG_LABEL UserIam::Common::LABEL_USER_AUTH_SA
42
43 namespace OHOS {
44 namespace UserIam {
45 namespace UserAuth {
46 constexpr int32_t DEFAULT_VALUE = -1;
47 const std::string UI_EXTENSION_TYPE_SET = "sysDialog/userAuth";
48
WidgetContext(uint64_t contextId,const ContextFactory::AuthWidgetContextPara & para,std::shared_ptr<ContextCallback> callback)49 WidgetContext::WidgetContext(uint64_t contextId, const ContextFactory::AuthWidgetContextPara ¶,
50 std::shared_ptr<ContextCallback> callback)
51 : contextId_(contextId), description_("UserAuthWidget"), callerCallback_(callback), hasStarted_(false),
52 latestError_(ResultCode::GENERAL_ERROR), para_(para), schedule_(nullptr), connection_(nullptr)
53 {
54 }
55
~WidgetContext()56 WidgetContext::~WidgetContext()
57 {
58 IAM_LOGI("release WidgetContext");
59 }
60
Start()61 bool WidgetContext::Start()
62 {
63 std::lock_guard<std::recursive_mutex> lock(mutex_);
64 IAM_LOGI("%{public}s start", description_.c_str());
65 if (hasStarted_) {
66 IAM_LOGI("%{public}s context has started, cannot start again", description_.c_str());
67 return false;
68 }
69 hasStarted_ = true;
70 return OnStart();
71 }
72
Stop()73 bool WidgetContext::Stop()
74 {
75 IAM_LOGI("%{public}s start", description_.c_str());
76 return OnStop();
77 }
78
GetContextId() const79 uint64_t WidgetContext::GetContextId() const
80 {
81 return contextId_;
82 }
83
GetContextType() const84 ContextType WidgetContext::GetContextType() const
85 {
86 return WIDGET_AUTH_CONTEXT;
87 }
88
GetScheduleNode(uint64_t scheduleId) const89 std::shared_ptr<ScheduleNode> WidgetContext::GetScheduleNode(uint64_t scheduleId) const
90 {
91 return nullptr;
92 }
93
GetTokenId() const94 uint32_t WidgetContext::GetTokenId() const
95 {
96 return para_.tokenId;
97 }
98
GetLatestError() const99 int32_t WidgetContext::GetLatestError() const
100 {
101 return latestError_;
102 }
103
SetLatestError(int32_t error)104 void WidgetContext::SetLatestError(int32_t error)
105 {
106 if (error != ResultCode::SUCCESS) {
107 latestError_ = error;
108 }
109 }
110
BuildSchedule()111 bool WidgetContext::BuildSchedule()
112 {
113 schedule_ = Common::MakeShared<WidgetScheduleNodeImpl>();
114 IF_FALSE_LOGE_AND_RETURN_VAL(schedule_ != nullptr, false);
115 schedule_->SetCallback(shared_from_this());
116 return true;
117 }
118
GetAuthContextCallback(AuthType authType,AuthTrustLevel authTrustLevel,sptr<IamCallbackInterface> & iamCallback)119 std::shared_ptr<ContextCallback> WidgetContext::GetAuthContextCallback(AuthType authType,
120 AuthTrustLevel authTrustLevel, sptr<IamCallbackInterface> &iamCallback)
121 {
122 auto widgetCallback = ContextCallback::NewInstance(iamCallback, TRACE_AUTH_USER_SECURITY);
123 if (widgetCallback == nullptr) {
124 IAM_LOGE("failed to construct context callback");
125 Attributes extraInfo;
126 iamCallback->OnResult(ResultCode::GENERAL_ERROR, extraInfo);
127 return nullptr;
128 }
129 widgetCallback->SetTraceCallerName(para_.callerName);
130 widgetCallback->SetTraceRequestContextId(contextId_);
131 widgetCallback->SetTraceAuthTrustLevel(authTrustLevel);
132 widgetCallback->SetTraceAuthType(authType);
133 return widgetCallback;
134 }
135
BuildTask(const std::vector<uint8_t> & challenge,AuthType authType,AuthTrustLevel authTrustLevel)136 std::shared_ptr<Context> WidgetContext::BuildTask(const std::vector<uint8_t> &challenge,
137 AuthType authType, AuthTrustLevel authTrustLevel)
138 {
139 IF_FALSE_LOGE_AND_RETURN_VAL(callerCallback_ != nullptr, nullptr);
140 auto userId = para_.userId;
141 auto tokenId = WidgetClient::Instance().GetAuthTokenId();
142 IAM_LOGI("Real userId: %{public}d, Real tokenId: %{public}u", userId, tokenId);
143 sptr<IamCallbackInterface> iamCallback(new (std::nothrow) WidgetContextCallbackImpl(weak_from_this(),
144 static_cast<int32_t>(authType)));
145 IF_FALSE_LOGE_AND_RETURN_VAL(iamCallback != nullptr, nullptr);
146 auto widgetCallback = GetAuthContextCallback(authType, authTrustLevel, iamCallback);
147 IF_FALSE_LOGE_AND_RETURN_VAL(widgetCallback != nullptr, nullptr);
148
149 Authentication::AuthenticationPara para = {};
150 para.tokenId = tokenId;
151 para.userId = userId;
152 para.authType = authType;
153 para.atl = authTrustLevel;
154 para.challenge = challenge;
155 para.endAfterFirstFail = true;
156 para.callerName = para_.callerName;
157 para.sdkVersion = para_.sdkVersion;
158 auto context = ContextFactory::CreateSimpleAuthContext(para, widgetCallback);
159 if (context == nullptr || !ContextPool::Instance().Insert(context)) {
160 IAM_LOGE("failed to insert context");
161 Attributes extraInfo;
162 widgetCallback->OnResult(ResultCode::GENERAL_ERROR, extraInfo);
163 return nullptr;
164 }
165 widgetCallback->SetTraceAuthContextId(context->GetContextId());
166 widgetCallback->SetCleaner(ContextHelper::Cleaner(context));
167 std::lock_guard<std::recursive_mutex> lock(mutex_);
168 return context;
169 }
170
OnStart()171 bool WidgetContext::OnStart()
172 {
173 IAM_LOGI("%{public}s start", description_.c_str());
174 if (!BuildSchedule()) {
175 IAM_LOGE("failed to create widget schedule");
176 return false;
177 }
178 WidgetClient::Instance().SetWidgetContextId(GetContextId());
179 WidgetClient::Instance().SetWidgetParam(para_.widgetParam);
180 WidgetClient::Instance().SetAuthTypeList(para_.authTypeList);
181 WidgetClient::Instance().SetWidgetSchedule(schedule_);
182 WidgetClient::Instance().SetChallenge(para_.challenge);
183 WidgetClient::Instance().SetCallingBundleName(para_.callingBundleName);
184 schedule_->StartSchedule();
185
186 IAM_LOGI("WidgetContext start success.");
187 return true;
188 }
189
OnResult(int32_t resultCode,const std::shared_ptr<Attributes> & scheduleResultAttr)190 void WidgetContext::OnResult(int32_t resultCode, const std::shared_ptr<Attributes> &scheduleResultAttr)
191 {
192 IAM_LOGI("%{public}s receive result code %{public}d", description_.c_str(), resultCode);
193 }
194
OnStop()195 bool WidgetContext::OnStop()
196 {
197 // response app.cancel()
198 IAM_LOGI("%{public}s start", description_.c_str());
199 End(ResultCode::CANCELED);
200 return true;
201 }
202
AuthResult(int32_t resultCode,int32_t at,const Attributes & finalResult)203 void WidgetContext::AuthResult(int32_t resultCode, int32_t at, const Attributes &finalResult)
204 {
205 IAM_LOGI("recv task result: %{public}d, authType: %{public}d", resultCode, at);
206 int32_t remainTimes = -1;
207 int32_t freezingTime = -1;
208 if (!finalResult.GetInt32Value(Attributes::ATTR_REMAIN_TIMES, remainTimes)) {
209 IAM_LOGI("get remainTimes failed.");
210 }
211 if (!finalResult.GetInt32Value(Attributes::ATTR_FREEZING_TIME, freezingTime)) {
212 IAM_LOGI("get freezingTime failed.");
213 }
214 AuthType authType = static_cast<AuthType>(at);
215 WidgetClient::Instance().ReportWidgetResult(resultCode, authType, freezingTime, remainTimes);
216 IF_FALSE_LOGE_AND_RETURN(schedule_ != nullptr);
217 IF_FALSE_LOGE_AND_RETURN(callerCallback_ != nullptr);
218 callerCallback_->SetTraceAuthType(authType);
219 IAM_LOGI("call schedule:");
220 if (resultCode == ResultCode::SUCCESS) {
221 finalResult.GetUint8ArrayValue(Attributes::ATTR_SIGNATURE, authResultInfo_.token);
222 authResultInfo_.authType = authType;
223 schedule_->SuccessAuth(authType);
224 } else {
225 // failed
226 SetLatestError(resultCode);
227 schedule_->StopAuthList({authType});
228 }
229 }
230
231 // WidgetScheduleNodeCallback
LaunchWidget()232 bool WidgetContext::LaunchWidget()
233 {
234 IAM_LOGI("launch widget");
235 if (!ConnectExtension()) {
236 IAM_LOGE("failed to launch widget.");
237 return false;
238 }
239 return true;
240 }
241
ExecuteAuthList(const std::set<AuthType> & authTypeList)242 void WidgetContext::ExecuteAuthList(const std::set<AuthType> &authTypeList)
243 {
244 IAM_LOGI("execute auth list");
245 // create task, and start it
246 std::lock_guard<std::recursive_mutex> lock(mutex_);
247 for (auto &authType : authTypeList) {
248 auto task = BuildTask(para_.challenge, authType, para_.atl);
249 if (task == nullptr) {
250 IAM_LOGE("failed to create task, authType: %{public}s", AuthType2Str(authType).c_str());
251 continue;
252 }
253 task->Start();
254 TaskInfo taskInfo {
255 .authType = authType,
256 .task = task
257 };
258 runTaskInfoList_.push_back(taskInfo);
259 }
260 }
261
EndAuthAsCancel()262 void WidgetContext::EndAuthAsCancel()
263 {
264 IAM_LOGI("end auth as cancel");
265 std::lock_guard<std::recursive_mutex> lock(mutex_);
266 // report CANCELED to App
267 End(ResultCode::CANCELED);
268 }
269
EndAuthAsNaviPin()270 void WidgetContext::EndAuthAsNaviPin()
271 {
272 IAM_LOGI("end auth as navi pin");
273 std::lock_guard<std::recursive_mutex> lock(mutex_);
274 // report CANCELED_FROM_WIDGET to App
275 End(ResultCode::CANCELED_FROM_WIDGET);
276 }
277
EndAuthAsWidgetParaInvalid()278 void WidgetContext::EndAuthAsWidgetParaInvalid()
279 {
280 IAM_LOGI("end auth as widget para invalid");
281 std::lock_guard<std::recursive_mutex> lock(mutex_);
282 End(ResultCode::INVALID_PARAMETERS);
283 }
284
StopAuthList(const std::vector<AuthType> & authTypeList)285 void WidgetContext::StopAuthList(const std::vector<AuthType> &authTypeList)
286 {
287 IAM_LOGI("stop auth list");
288 std::lock_guard<std::recursive_mutex> lock(mutex_);
289 for (auto &authType : authTypeList) {
290 auto it = std::find_if(runTaskInfoList_.begin(),
291 runTaskInfoList_.end(), [authType] (const TaskInfo &taskInfo) {
292 return (taskInfo.authType == authType);
293 });
294 if (it != runTaskInfoList_.end()) {
295 if (it->task == nullptr) {
296 IAM_LOGE("task is nullptr");
297 return;
298 }
299 it->task->Stop();
300 runTaskInfoList_.erase(it);
301 }
302 }
303 }
304
SuccessAuth(AuthType authType)305 void WidgetContext::SuccessAuth(AuthType authType)
306 {
307 IAM_LOGI("success auth. authType:%{public}d", static_cast<int32_t>(authType));
308 std::lock_guard<std::recursive_mutex> lock(mutex_);
309 // report success to App
310 End(ResultCode::SUCCESS);
311 }
312
ConnectExtensionAbility(const AAFwk::Want & want,const std::string commandStr)313 int32_t WidgetContext::ConnectExtensionAbility(const AAFwk::Want &want, const std::string commandStr)
314 {
315 IAM_LOGI("ConnectExtensionAbility start");
316 if (connection_ != nullptr) {
317 IAM_LOGE("invalid connection_");
318 return ERR_INVALID_OPERATION;
319 }
320 connection_ = sptr<UIExtensionAbilityConnection>(new (std::nothrow) UIExtensionAbilityConnection(commandStr));
321 if (connection_ == nullptr) {
322 IAM_LOGE("new connection error.");
323 return ERR_NO_MEMORY;
324 }
325
326 std::string identity = IPCSkeleton::ResetCallingIdentity();
327 auto ret = AAFwk::ExtensionManagerClient::GetInstance().ConnectServiceExtensionAbility(want, connection_, nullptr,
328 DEFAULT_VALUE);
329 IPCSkeleton::SetCallingIdentity(identity);
330 IAM_LOGI("ConnectExtensionAbility errCode=%{public}d", ret);
331 return ret;
332 }
333
ConnectExtension()334 bool WidgetContext::ConnectExtension()
335 {
336 std::string tmp = BuildStartCommand();
337 IAM_LOGI("start command: %{public}s", tmp.c_str());
338
339 AAFwk::Want want;
340 std::string bundleName = "com.ohos.systemui";
341 std::string abilityName = "com.ohos.systemui.dialog";
342 want.SetElementName(bundleName, abilityName);
343 auto ret = ConnectExtensionAbility(want, tmp);
344 if (ret != ERR_OK) {
345 UserIam::UserAuth::ReportSystemFault(Common::GetNowTimeString(), "userauthservice");
346 IAM_LOGE("ConnectExtensionAbility failed.");
347 return false;
348 }
349 return true;
350 }
351
DisconnectExtension()352 bool WidgetContext::DisconnectExtension()
353 {
354 if (connection_ == nullptr) {
355 IAM_LOGE("invalid connection handle");
356 return false;
357 }
358 ErrCode ret = AAFwk::ExtensionManagerClient::GetInstance().DisconnectAbility(connection_);
359 if (ret != ERR_OK) {
360 IAM_LOGE("disconnect extension ability failed ret: %{public}d.", ret);
361 return false;
362 }
363 return true;
364 }
365
End(const ResultCode & resultCode)366 void WidgetContext::End(const ResultCode &resultCode)
367 {
368 IAM_LOGI("in End, resultCode: %{public}d", static_cast<int32_t>(resultCode));
369 WidgetClient::Instance().Reset();
370 StopAllRunTask();
371 if (resultCode != ResultCode::SUCCESS) {
372 IAM_LOGI("Try to disconnect extesnion");
373 if (!DisconnectExtension()) {
374 IAM_LOGE("failed to release launch widget.");
375 }
376 }
377 IF_FALSE_LOGE_AND_RETURN(callerCallback_ != nullptr);
378 Attributes attr;
379 if (resultCode == ResultCode::SUCCESS) {
380 if (!attr.SetInt32Value(Attributes::ATTR_AUTH_TYPE, authResultInfo_.authType)) {
381 IAM_LOGE("set auth type failed.");
382 callerCallback_->OnResult(ResultCode::GENERAL_ERROR, attr);
383 return;
384 }
385 if (authResultInfo_.token.size() > 0) {
386 if (!attr.SetUint8ArrayValue(Attributes::ATTR_SIGNATURE, authResultInfo_.token)) {
387 IAM_LOGE("set signature token failed.");
388 callerCallback_->OnResult(ResultCode::GENERAL_ERROR, attr);
389 return;
390 }
391 }
392 }
393 callerCallback_->OnResult(resultCode, attr);
394 }
395
StopAllRunTask()396 void WidgetContext::StopAllRunTask()
397 {
398 std::lock_guard<std::recursive_mutex> lock(mutex_);
399 for (auto &taskInfo : runTaskInfoList_) {
400 IAM_LOGI("stop task");
401 taskInfo.task->Stop();
402 }
403 runTaskInfoList_.clear();
404 }
405
BuildStartCommand()406 std::string WidgetContext::BuildStartCommand()
407 {
408 WidgetCmdParameters widgetCmdParameters;
409 widgetCmdParameters.uiExtensionType = UI_EXTENSION_TYPE_SET;
410 widgetCmdParameters.useriamCmdData.widgetContextId = GetContextId();
411 widgetCmdParameters.useriamCmdData.title = para_.widgetParam.title;
412 widgetCmdParameters.useriamCmdData.windowModeType = WinModeType2Str(para_.widgetParam.windowMode);
413 widgetCmdParameters.useriamCmdData.navigationButtonText = para_.widgetParam.navigationButtonText;
414 auto it = para_.authProfileMap.find(AuthType::PIN);
415 if (it != para_.authProfileMap.end()) {
416 widgetCmdParameters.useriamCmdData.pinSubType = PinSubType2Str(static_cast<PinSubType>(it->second.pinSubType));
417 }
418 std::vector<std::string> typeList;
419 for (auto &item : para_.authProfileMap) {
420 auto &at = item.first;
421 auto &profile = item.second;
422 typeList.push_back(AuthType2Str(at));
423 WidgetCommand::Cmd cmd {
424 .event = CMD_NOTIFY_AUTH_START,
425 .version = NOTICE_VERSION_STR,
426 .type = AuthType2Str(at)
427 };
428 if (at == AuthType::FINGERPRINT && !profile.sensorInfo.empty()) {
429 cmd.sensorInfo = profile.sensorInfo;
430 }
431 cmd.remainAttempts = profile.remainTimes;
432 cmd.lockoutDuration = profile.freezingTime;
433 widgetCmdParameters.useriamCmdData.cmdList.push_back(cmd);
434 }
435 widgetCmdParameters.useriamCmdData.typeList = typeList;
436
437 nlohmann::json root = widgetCmdParameters;
438 std::string cmdData = root.dump();
439 return cmdData;
440 }
441 } // namespace UserAuth
442 } // namespace UserIam
443 } // namespace OHOS
444