1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
18 #include <android/binder_process.h>
19 #include <face.sysprop.h>
20 #include <gtest/gtest.h>
21
22 #include <android-base/logging.h>
23
24 #include "Face.h"
25 #include "FakeLockoutTracker.h"
26 #include "util/Util.h"
27
28 using namespace ::android::face::virt;
29 using namespace ::aidl::android::hardware::biometrics::face;
30
31 namespace aidl::android::hardware::biometrics::face {
32
33 class TestSessionCallback : public BnSessionCallback {
34 public:
onChallengeGenerated(int64_t)35 ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
36 return ndk::ScopedAStatus::ok();
37 };
onChallengeRevoked(int64_t)38 ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
39 return ndk::ScopedAStatus::ok();
40 };
onError(face::Error,int32_t)41 ::ndk::ScopedAStatus onError(face::Error, int32_t /*vendorCode*/) override {
42 return ndk::ScopedAStatus::ok();
43 };
onEnrollmentProgress(int32_t,int32_t)44 ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
45 int32_t /*remaining*/) override {
46 return ndk::ScopedAStatus::ok();
47 };
onAuthenticationSucceeded(int32_t,const keymaster::HardwareAuthToken &)48 ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
49 const keymaster::HardwareAuthToken&) override {
50 return ndk::ScopedAStatus::ok();
51 };
onAuthenticationFailed()52 ::ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); };
onInteractionDetected()53 ::ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); };
onEnrollmentsEnumerated(const std::vector<int32_t> &)54 ::ndk::ScopedAStatus onEnrollmentsEnumerated(const std::vector<int32_t>&) override {
55 return ndk::ScopedAStatus::ok();
56 };
onEnrollmentsRemoved(const std::vector<int32_t> &)57 ::ndk::ScopedAStatus onEnrollmentsRemoved(
58 const std::vector<int32_t>& /*enrollmentIds*/) override {
59 return ndk::ScopedAStatus::ok();
60 };
onAuthenticatorIdRetrieved(int64_t)61 ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
62 return ndk::ScopedAStatus::ok();
63 };
onAuthenticatorIdInvalidated(int64_t)64 ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
65 return ndk::ScopedAStatus::ok();
66 };
onEnrollmentFrame(const EnrollmentFrame &)67 ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame&) override {
68 return ndk::ScopedAStatus::ok();
69 }
onFeaturesRetrieved(const std::vector<Feature> &)70 ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>&) {
71 return ndk::ScopedAStatus::ok();
72 };
onFeatureSet(Feature)73 ::ndk::ScopedAStatus onFeatureSet(Feature) override { return ndk::ScopedAStatus::ok(); }
onSessionClosed()74 ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
onAuthenticationFrame(const AuthenticationFrame &)75 ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame&) override {
76 return ndk::ScopedAStatus::ok();
77 }
78
onLockoutTimed(int64_t timeLeft)79 ndk::ScopedAStatus onLockoutTimed(int64_t timeLeft) override {
80 mLockoutTimed++;
81 mTimeLeft = timeLeft;
82 return ndk::ScopedAStatus::ok();
83 };
onLockoutPermanent()84 ::ndk::ScopedAStatus onLockoutPermanent() override {
85 mLockoutPermanent++;
86 return ndk::ScopedAStatus::ok();
87 };
onLockoutCleared()88 ::ndk::ScopedAStatus onLockoutCleared() override {
89 mTimeLeft = 0;
90 mLockoutTimed = 0;
91 mLockoutPermanent = 0;
92 return ndk::ScopedAStatus::ok();
93 };
94
95 int64_t mTimeLeft = 0;
96 int mLockoutTimed = 0;
97 int mLockoutPermanent = 0;
98 };
99
100 class FakeLockoutTrackerTest : public ::testing::Test {
101 protected:
102 static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
103 static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
104 static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
105
SetUp()106 void SetUp() override {
107 Face::cfg().set<std::int32_t>("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD);
108 Face::cfg().set<std::int32_t>("lockout_timed_duration", LOCKOUT_TIMED_DURATION);
109 Face::cfg().set<std::int32_t>("lockout_permanent_threshold", LOCKOUT_PERMANENT_THRESHOLD);
110 Face::cfg().set<bool>("lockout_enable", false);
111 Face::cfg().set<bool>("lockout", false);
112 mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
113 }
114
TearDown()115 void TearDown() override {
116 // reset to default
117 Face::cfg().set<std::int32_t>("lockout_timed_threshold", 5);
118 Face::cfg().set<std::int32_t>("lockout_timed_duration", 20);
119 Face::cfg().set<std::int32_t>("lockout_permanent_threshold", 10000);
120 Face::cfg().set<bool>("lockout_enable", false);
121 Face::cfg().set<bool>("lockout", false);
122 }
123
124 FakeLockoutTracker mLockoutTracker;
125 std::shared_ptr<TestSessionCallback> mCallback;
126 };
127
TEST_F(FakeLockoutTrackerTest,addFailedAttemptDisable)128 TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
129 Face::cfg().set<bool>("lockout_enable", false);
130 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
131 mLockoutTracker.addFailedAttempt(mCallback.get());
132 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
133 ASSERT_EQ(0, mCallback->mLockoutTimed);
134 }
135
TEST_F(FakeLockoutTrackerTest,addFailedAttemptPermanent)136 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
137 Face::cfg().set<bool>("lockout_enable", true);
138 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
139 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
140 mLockoutTracker.addFailedAttempt(mCallback.get());
141 ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
142 ASSERT_EQ(0, mCallback->mLockoutPermanent);
143 mLockoutTracker.addFailedAttempt(mCallback.get());
144 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
145 ASSERT_EQ(1, mCallback->mLockoutPermanent);
146 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
147 ASSERT_EQ(2, mCallback->mLockoutPermanent);
148 }
149
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockoutTimed)150 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
151 Face::cfg().set<bool>("lockout_enable", true);
152 Face::cfg().set<bool>("lockout_timed_enable", true);
153 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
154 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
155 mLockoutTracker.addFailedAttempt(mCallback.get());
156 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
157 ASSERT_EQ(1, mCallback->mLockoutTimed);
158 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
159 ASSERT_EQ(2, mCallback->mLockoutTimed);
160 // time left
161 int N = 5;
162 int64_t prevTimeLeft = INT_MAX;
163 for (int i = 0; i < N; i++) {
164 SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
165 int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
166 ASSERT_TRUE(currTimeLeft < prevTimeLeft);
167 prevTimeLeft = currTimeLeft;
168 }
169 SLEEP_MS(LOCKOUT_TIMED_DURATION / N);
170 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
171 }
172
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockout_TimedThenPermanent)173 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
174 Face::cfg().set<bool>("lockout_enable", true);
175 Face::cfg().set<bool>("lockout_timed_enable", true);
176 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
177 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
178 mLockoutTracker.addFailedAttempt(mCallback.get());
179 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
180 SLEEP_MS(LOCKOUT_TIMED_DURATION + 20);
181 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
182 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - LOCKOUT_TIMED_THRESHOLD; i++)
183 mLockoutTracker.addFailedAttempt(mCallback.get());
184 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
185 }
186
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockoutTimedTwice)187 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
188 Face::cfg().set<bool>("lockout_enable", true);
189 Face::cfg().set<bool>("lockout_timed_enable", true);
190 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
191 ASSERT_EQ(0, mCallback->mLockoutTimed);
192 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
193 mLockoutTracker.addFailedAttempt(mCallback.get());
194 SLEEP_MS(LOCKOUT_TIMED_DURATION / 2);
195 mLockoutTracker.addFailedAttempt(mCallback.get());
196 SLEEP_MS(LOCKOUT_TIMED_DURATION);
197 ASSERT_EQ(2, mCallback->mLockoutTimed);
198 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
199 SLEEP_MS(LOCKOUT_TIMED_DURATION);
200 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
201 }
202
TEST_F(FakeLockoutTrackerTest,resetLockout)203 TEST_F(FakeLockoutTrackerTest, resetLockout) {
204 Face::cfg().set<bool>("lockout_enable", true);
205 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
206 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
207 mLockoutTracker.addFailedAttempt(mCallback.get());
208 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
209 mLockoutTracker.reset();
210 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
211 }
212
213 } // namespace aidl::android::hardware::biometrics::face
214
main(int argc,char ** argv)215 int main(int argc, char** argv) {
216 testing::InitGoogleTest(&argc, argv);
217 ABinderProcess_startThreadPool();
218 return RUN_ALL_TESTS();
219 }
220