1 /* 2 * Copyright (C) 2022 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 package com.android.server.credentials; 18 19 import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS; 20 import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; 21 import static android.content.Context.CREDENTIAL_SERVICE; 22 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 23 24 import android.Manifest; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.UserIdInt; 28 import android.app.ActivityManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.PackageManager; 33 import android.credentials.ClearCredentialStateRequest; 34 import android.credentials.CreateCredentialException; 35 import android.credentials.CreateCredentialRequest; 36 import android.credentials.CredentialOption; 37 import android.credentials.CredentialProviderInfo; 38 import android.credentials.GetCredentialException; 39 import android.credentials.GetCredentialRequest; 40 import android.credentials.IClearCredentialStateCallback; 41 import android.credentials.ICreateCredentialCallback; 42 import android.credentials.ICredentialManager; 43 import android.credentials.IGetCredentialCallback; 44 import android.credentials.IPrepareGetCredentialCallback; 45 import android.credentials.ISetEnabledProvidersCallback; 46 import android.credentials.PrepareGetCredentialResponseInternal; 47 import android.credentials.RegisterCredentialDescriptionRequest; 48 import android.credentials.UnregisterCredentialDescriptionRequest; 49 import android.os.Binder; 50 import android.os.CancellationSignal; 51 import android.os.IBinder; 52 import android.os.ICancellationSignal; 53 import android.os.RemoteException; 54 import android.os.UserHandle; 55 import android.provider.DeviceConfig; 56 import android.provider.Settings; 57 import android.service.credentials.CallingAppInfo; 58 import android.service.credentials.CredentialProviderInfoFactory; 59 import android.service.credentials.PermissionUtils; 60 import android.text.TextUtils; 61 import android.util.Pair; 62 import android.util.Slog; 63 import android.util.SparseArray; 64 65 import com.android.internal.annotations.GuardedBy; 66 import com.android.server.credentials.metrics.ApiName; 67 import com.android.server.credentials.metrics.ApiStatus; 68 import com.android.server.infra.AbstractMasterSystemService; 69 import com.android.server.infra.SecureSettingsServiceNameResolver; 70 71 import java.util.ArrayList; 72 import java.util.HashMap; 73 import java.util.HashSet; 74 import java.util.LinkedHashSet; 75 import java.util.List; 76 import java.util.Map; 77 import java.util.Set; 78 import java.util.function.Consumer; 79 import java.util.stream.Collectors; 80 81 /** 82 * Entry point service for credential management. 83 * 84 * <p>This service provides the {@link ICredentialManager} implementation and keeps a list of {@link 85 * CredentialManagerServiceImpl} per user; the real work is done by {@link 86 * CredentialManagerServiceImpl} itself. 87 */ 88 public final class CredentialManagerService 89 extends AbstractMasterSystemService< 90 CredentialManagerService, CredentialManagerServiceImpl> { 91 92 private static final String TAG = "CredManSysService"; 93 private static final String PERMISSION_DENIED_ERROR = "permission_denied"; 94 private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR = 95 "Caller is missing WRITE_SECURE_SETTINGS permission"; 96 private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER = 97 "enable_credential_manager"; 98 99 private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API = 100 "enable_credential_description_api"; 101 102 private final Context mContext; 103 104 /** Cache of system service list per user id. */ 105 @GuardedBy("mLock") 106 private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList = 107 new SparseArray<>(); 108 109 /** Cache of all ongoing request sessions per user id. */ 110 @GuardedBy("mLock") 111 private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions = 112 new SparseArray<>(); 113 114 private final SessionManager mSessionManager = new SessionManager(); 115 CredentialManagerService(@onNull Context context)116 public CredentialManagerService(@NonNull Context context) { 117 super( 118 context, 119 new SecureSettingsServiceNameResolver( 120 context, Settings.Secure.CREDENTIAL_SERVICE, /* isMultipleMode= */ true), 121 null, 122 PACKAGE_UPDATE_POLICY_REFRESH_EAGER); 123 mContext = context; 124 } 125 126 @NonNull 127 @GuardedBy("mLock") constructSystemServiceListLocked( int resolvedUserId)128 private List<CredentialManagerServiceImpl> constructSystemServiceListLocked( 129 int resolvedUserId) { 130 List<CredentialManagerServiceImpl> services = new ArrayList<>(); 131 List<CredentialProviderInfo> serviceInfos = 132 CredentialProviderInfoFactory.getAvailableSystemServices( 133 mContext, 134 resolvedUserId, 135 /* disableSystemAppVerificationForTests= */ false, 136 new HashSet<>()); 137 serviceInfos.forEach( 138 info -> { 139 services.add( 140 new CredentialManagerServiceImpl(this, mLock, resolvedUserId, 141 info)); 142 }); 143 return services; 144 } 145 146 @Override getServiceSettingsProperty()147 protected String getServiceSettingsProperty() { 148 return Settings.Secure.CREDENTIAL_SERVICE; 149 } 150 151 @Override // from AbstractMasterSystemService newServiceLocked( @serIdInt int resolvedUserId, boolean disabled)152 protected CredentialManagerServiceImpl newServiceLocked( 153 @UserIdInt int resolvedUserId, boolean disabled) { 154 // This method should not be called for CredentialManagerService as it is configured to use 155 // multiple services. 156 Slog.w( 157 TAG, 158 "Should not be here - CredentialManagerService is configured to use " 159 + "multiple services"); 160 return null; 161 } 162 163 @Override // from SystemService onStart()164 public void onStart() { 165 publishBinderService(CREDENTIAL_SERVICE, new CredentialManagerServiceStub()); 166 } 167 168 @Override // from AbstractMasterSystemService 169 @GuardedBy("mLock") newServiceListLocked( int resolvedUserId, boolean disabled, String[] serviceNames)170 protected List<CredentialManagerServiceImpl> newServiceListLocked( 171 int resolvedUserId, boolean disabled, String[] serviceNames) { 172 getOrConstructSystemServiceListLock(resolvedUserId); 173 if (serviceNames == null || serviceNames.length == 0) { 174 return new ArrayList<>(); 175 } 176 List<CredentialManagerServiceImpl> serviceList = new ArrayList<>(serviceNames.length); 177 for (String serviceName : serviceNames) { 178 if (TextUtils.isEmpty(serviceName)) { 179 continue; 180 } 181 try { 182 serviceList.add( 183 new CredentialManagerServiceImpl(this, mLock, resolvedUserId, serviceName)); 184 } catch (PackageManager.NameNotFoundException | SecurityException e) { 185 Slog.e(TAG, "Unable to add serviceInfo : ", e); 186 } 187 } 188 return serviceList; 189 } 190 191 @GuardedBy("mLock") 192 @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same 193 // this.mLock handlePackageRemovedMultiModeLocked(String packageName, int userId)194 protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) { 195 List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); 196 if (services == null) { 197 return; 198 } 199 200 List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>(); 201 for (CredentialManagerServiceImpl service : services) { 202 if (service != null) { 203 CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo(); 204 ComponentName componentName = 205 credentialProviderInfo.getServiceInfo().getComponentName(); 206 if (packageName.equals(componentName.getPackageName())) { 207 servicesToBeRemoved.add(service); 208 } 209 } 210 } 211 212 // Iterate over all the services to be removed, and remove them from the user configurable 213 // services cache, the system services cache as well as the setting key-value pair. 214 for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { 215 removeServiceFromCache(serviceToBeRemoved, userId); 216 removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); 217 removeServiceFromMultiModeSettings(serviceToBeRemoved.getComponentName() 218 .flattenToString(), userId); 219 CredentialDescriptionRegistry.forUser(userId) 220 .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); 221 } 222 } 223 224 @GuardedBy("mLock") removeServiceFromSystemServicesCache( CredentialManagerServiceImpl serviceToBeRemoved, int userId)225 private void removeServiceFromSystemServicesCache( 226 CredentialManagerServiceImpl serviceToBeRemoved, int userId) { 227 if (mSystemServicesCacheList.get(userId) != null) { 228 mSystemServicesCacheList.get(userId).remove(serviceToBeRemoved); 229 } 230 } 231 232 @GuardedBy("mLock") getOrConstructSystemServiceListLock( int resolvedUserId)233 private List<CredentialManagerServiceImpl> getOrConstructSystemServiceListLock( 234 int resolvedUserId) { 235 List<CredentialManagerServiceImpl> services = mSystemServicesCacheList.get(resolvedUserId); 236 if (services == null || services.size() == 0) { 237 services = constructSystemServiceListLocked(resolvedUserId); 238 mSystemServicesCacheList.put(resolvedUserId, services); 239 } 240 return services; 241 } 242 hasWriteSecureSettingsPermission()243 private boolean hasWriteSecureSettingsPermission() { 244 return hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); 245 } 246 verifyGetProvidersPermission()247 private void verifyGetProvidersPermission() throws SecurityException { 248 if (hasPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)) { 249 return; 250 } 251 252 if (hasPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)) { 253 return; 254 } 255 256 throw new SecurityException( 257 "Caller is missing permission: QUERY_ALL_PACKAGES or " 258 + "LIST_ENABLED_CREDENTIAL_PROVIDERS"); 259 } 260 hasPermission(String permission)261 private boolean hasPermission(String permission) { 262 final boolean result = 263 mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED; 264 if (!result) { 265 Slog.e(TAG, "Caller does not have permission: " + permission); 266 } 267 return result; 268 } 269 runForUser(@onNull final Consumer<CredentialManagerServiceImpl> c)270 private void runForUser(@NonNull final Consumer<CredentialManagerServiceImpl> c) { 271 final int userId = UserHandle.getCallingUserId(); 272 final long origId = Binder.clearCallingIdentity(); 273 try { 274 synchronized (mLock) { 275 final List<CredentialManagerServiceImpl> services = 276 getCredentialProviderServicesLocked(userId); 277 for (CredentialManagerServiceImpl s : services) { 278 c.accept(s); 279 } 280 } 281 } finally { 282 Binder.restoreCallingIdentity(origId); 283 } 284 } 285 getPrimaryProvidersForUserId(Context context, int userId)286 private static Set<ComponentName> getPrimaryProvidersForUserId(Context context, int userId) { 287 final int resolvedUserId = ActivityManager.handleIncomingUser( 288 Binder.getCallingPid(), Binder.getCallingUid(), 289 userId, false, false, 290 "getPrimaryProvidersForUserId", null); 291 SecureSettingsServiceNameResolver resolver = new SecureSettingsServiceNameResolver( 292 context, Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, 293 /* isMultipleMode= */ true); 294 String[] serviceNames = resolver.readServiceNameList(resolvedUserId); 295 if (serviceNames == null) { 296 return new HashSet<ComponentName>(); 297 } 298 299 Set<ComponentName> services = new HashSet<>(); 300 for (String serviceName : serviceNames) { 301 ComponentName compName = ComponentName.unflattenFromString(serviceName); 302 if (compName == null) { 303 Slog.w( 304 TAG, 305 "Primary provider component name unflatten from string error: " 306 + serviceName); 307 continue; 308 } 309 services.add(compName); 310 } 311 return services; 312 } 313 314 @GuardedBy("mLock") getCredentialProviderServicesLocked(int userId)315 private List<CredentialManagerServiceImpl> getCredentialProviderServicesLocked(int userId) { 316 List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>(); 317 List<CredentialManagerServiceImpl> userConfigurableServices = 318 getServiceListForUserLocked(userId); 319 if (userConfigurableServices != null && !userConfigurableServices.isEmpty()) { 320 concatenatedServices.addAll(userConfigurableServices); 321 } 322 concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId)); 323 return concatenatedServices; 324 } 325 isCredentialDescriptionApiEnabled()326 public static boolean isCredentialDescriptionApiEnabled() { 327 final long origId = Binder.clearCallingIdentity(); 328 try { 329 return DeviceConfig.getBoolean( 330 DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, 331 false); 332 } finally { 333 Binder.restoreCallingIdentity(origId); 334 } 335 } 336 337 @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked 338 // to be guarded by 'service.mLock', which is the same as mLock. initiateProviderSessionsWithActiveContainers( GetRequestSession session, Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> activeCredentialContainers)339 private List<ProviderSession> initiateProviderSessionsWithActiveContainers( 340 GetRequestSession session, 341 Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> 342 activeCredentialContainers) { 343 List<ProviderSession> providerSessions = new ArrayList<>(); 344 for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result : 345 activeCredentialContainers) { 346 ProviderSession providerSession = ProviderRegistryGetSession.createNewSession( 347 mContext, 348 UserHandle.getCallingUserId(), 349 session, 350 session.mClientAppInfo, 351 result.second.mPackageName, 352 result.first); 353 providerSessions.add(providerSession); 354 session.addProviderSession(providerSession.getComponentName(), providerSession); 355 } 356 return providerSessions; 357 } 358 359 @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked 360 // to be guarded by 'service.mLock', which is the same as mLock. initiateProviderSessionsWithActiveContainers( PrepareGetRequestSession session, Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> activeCredentialContainers)361 private List<ProviderSession> initiateProviderSessionsWithActiveContainers( 362 PrepareGetRequestSession session, 363 Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> 364 activeCredentialContainers) { 365 List<ProviderSession> providerSessions = new ArrayList<>(); 366 for (Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult> result : 367 activeCredentialContainers) { 368 ProviderSession providerSession = ProviderRegistryGetSession.createNewSession( 369 mContext, 370 UserHandle.getCallingUserId(), 371 session, 372 session.mClientAppInfo, 373 result.second.mPackageName, 374 result.first); 375 providerSessions.add(providerSession); 376 session.addProviderSession(providerSession.getComponentName(), providerSession); 377 } 378 return providerSessions; 379 } 380 381 382 @NonNull 383 private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> getFilteredResultFromRegistry(List<CredentialOption> options)384 getFilteredResultFromRegistry(List<CredentialOption> options) { 385 // Session for active/provisioned credential descriptions; 386 CredentialDescriptionRegistry registry = 387 CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); 388 389 // All requested credential descriptions based on the given request. 390 Set<Set<String>> requestedCredentialDescriptions = 391 options.stream() 392 .map( 393 getCredentialOption -> 394 new HashSet<>(getCredentialOption 395 .getCredentialRetrievalData() 396 .getStringArrayList( 397 CredentialOption.SUPPORTED_ELEMENT_KEYS))) 398 .collect(Collectors.toSet()); 399 400 // All requested credential descriptions based on the given request. 401 Set<CredentialDescriptionRegistry.FilterResult> filterResults = 402 registry.getMatchingProviders(requestedCredentialDescriptions); 403 404 Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> result = 405 new HashSet<>(); 406 407 for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) { 408 for (CredentialOption credentialOption : options) { 409 Set<String> requestedElementKeys = new HashSet<>( 410 credentialOption 411 .getCredentialRetrievalData() 412 .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); 413 if (CredentialDescriptionRegistry.checkForMatch(filterResult.mElementKeys, 414 requestedElementKeys)) { 415 result.add(new Pair<>(credentialOption, filterResult)); 416 } 417 } 418 } 419 return result; 420 } 421 422 @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked 423 // to be guarded by 'service.mLock', which is the same as mLock. initiateProviderSessions( RequestSession session, List<String> requestOptions)424 private List<ProviderSession> initiateProviderSessions( 425 RequestSession session, List<String> requestOptions) { 426 List<ProviderSession> providerSessions = new ArrayList<>(); 427 // Invoke all services of a user to initiate a provider session 428 runForUser( 429 (service) -> { 430 synchronized (mLock) { 431 ProviderSession providerSession = 432 service.initiateProviderSessionForRequestLocked( 433 session, requestOptions); 434 if (providerSession != null) { 435 providerSessions.add(providerSession); 436 } 437 } 438 }); 439 return providerSessions; 440 } 441 442 @Override 443 @GuardedBy("CredentialDescriptionRegistry.sLock") onUserStopped(@onNull TargetUser user)444 public void onUserStopped(@NonNull TargetUser user) { 445 super.onUserStopped(user); 446 CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier()); 447 } 448 constructCallingAppInfo( String realPackageName, int userId, @Nullable String origin)449 private CallingAppInfo constructCallingAppInfo( 450 String realPackageName, 451 int userId, 452 @Nullable String origin) { 453 final PackageInfo packageInfo; 454 CallingAppInfo callingAppInfo; 455 try { 456 packageInfo = 457 getContext() 458 .getPackageManager() 459 .getPackageInfoAsUser( 460 realPackageName, 461 PackageManager.PackageInfoFlags.of( 462 PackageManager.GET_SIGNING_CERTIFICATES), 463 userId); 464 callingAppInfo = new CallingAppInfo(realPackageName, packageInfo.signingInfo, origin); 465 } catch (PackageManager.NameNotFoundException e) { 466 Slog.e(TAG, "Issue while retrieving signatureInfo : ", e); 467 callingAppInfo = new CallingAppInfo(realPackageName, null, origin); 468 } 469 return callingAppInfo; 470 } 471 472 final class CredentialManagerServiceStub extends ICredentialManager.Stub { 473 @Override executeGetCredential( GetCredentialRequest request, IGetCredentialCallback callback, final String callingPackage)474 public ICancellationSignal executeGetCredential( 475 GetCredentialRequest request, 476 IGetCredentialCallback callback, 477 final String callingPackage) { 478 final long timestampBegan = System.nanoTime(); 479 Slog.i(TAG, "starting executeGetCredential with callingPackage: " 480 + callingPackage); 481 ICancellationSignal cancelTransport = CancellationSignal.createTransport(); 482 483 final int userId = UserHandle.getCallingUserId(); 484 final int callingUid = Binder.getCallingUid(); 485 enforceCallingPackage(callingPackage, callingUid); 486 487 validateGetCredentialRequest(request); 488 489 // New request session, scoped for this request only. 490 final GetRequestSession session = 491 new GetRequestSession( 492 getContext(), 493 mSessionManager, 494 mLock, 495 userId, 496 callingUid, 497 callback, 498 request, 499 constructCallingAppInfo(callingPackage, userId, request.getOrigin()), 500 getEnabledProvidersForUser(userId), 501 CancellationSignal.fromTransport(cancelTransport), 502 timestampBegan); 503 addSessionLocked(userId, session); 504 505 List<ProviderSession> providerSessions = 506 prepareProviderSessions(request, session); 507 508 if (providerSessions.isEmpty()) { 509 try { 510 callback.onError( 511 GetCredentialException.TYPE_NO_CREDENTIAL, 512 "No credentials available on this device."); 513 } catch (RemoteException e) { 514 Slog.e( 515 TAG, 516 "Issue invoking onError on IGetCredentialCallback " 517 + "callback: " 518 + e.getMessage()); 519 } 520 } 521 522 invokeProviderSessions(providerSessions); 523 return cancelTransport; 524 } 525 526 @Override executePrepareGetCredential( GetCredentialRequest request, IPrepareGetCredentialCallback prepareGetCredentialCallback, IGetCredentialCallback getCredentialCallback, final String callingPackage)527 public ICancellationSignal executePrepareGetCredential( 528 GetCredentialRequest request, 529 IPrepareGetCredentialCallback prepareGetCredentialCallback, 530 IGetCredentialCallback getCredentialCallback, 531 final String callingPackage) { 532 final long timestampBegan = System.nanoTime(); 533 ICancellationSignal cancelTransport = CancellationSignal.createTransport(); 534 535 if (request.getOrigin() != null) { 536 // Check privileged permissions 537 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); 538 } 539 enforcePermissionForAllowedProviders(request); 540 541 final int userId = UserHandle.getCallingUserId(); 542 final int callingUid = Binder.getCallingUid(); 543 enforceCallingPackage(callingPackage, callingUid); 544 545 final PrepareGetRequestSession session = 546 new PrepareGetRequestSession( 547 getContext(), 548 mSessionManager, 549 mLock, 550 userId, 551 callingUid, 552 getCredentialCallback, 553 request, 554 constructCallingAppInfo(callingPackage, userId, request.getOrigin()), 555 getEnabledProvidersForUser(userId), 556 CancellationSignal.fromTransport(cancelTransport), 557 timestampBegan, 558 prepareGetCredentialCallback); 559 560 List<ProviderSession> providerSessions = prepareProviderSessions(request, session); 561 562 if (providerSessions.isEmpty()) { 563 try { 564 prepareGetCredentialCallback.onResponse( 565 new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission( 566 mContext, 567 callingPackage, 568 Manifest.permission 569 .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS), 570 /*credentialResultTypes=*/null, 571 /*hasAuthenticationResults=*/false, 572 /*hasRemoteResults=*/false, 573 /*pendingIntent=*/null)); 574 } catch (RemoteException e) { 575 Slog.e( 576 TAG, 577 "Issue invoking onError on IGetCredentialCallback " 578 + "callback: " 579 + e.getMessage()); 580 } 581 } 582 583 invokeProviderSessions(providerSessions); 584 585 return cancelTransport; 586 } 587 prepareProviderSessions( GetCredentialRequest request, GetRequestSession session)588 private List<ProviderSession> prepareProviderSessions( 589 GetCredentialRequest request, 590 GetRequestSession session) { 591 List<ProviderSession> providerSessions; 592 593 if (isCredentialDescriptionApiEnabled()) { 594 List<CredentialOption> optionsThatRequireActiveCredentials = 595 request.getCredentialOptions().stream() 596 .filter(credentialOption -> credentialOption 597 .getCredentialRetrievalData() 598 .getStringArrayList( 599 CredentialOption 600 .SUPPORTED_ELEMENT_KEYS) != null) 601 .toList(); 602 603 List<CredentialOption> optionsThatDoNotRequireActiveCredentials = 604 request.getCredentialOptions().stream() 605 .filter(credentialOption -> credentialOption 606 .getCredentialRetrievalData() 607 .getStringArrayList( 608 CredentialOption 609 .SUPPORTED_ELEMENT_KEYS) == null) 610 .toList(); 611 612 List<ProviderSession> sessionsWithoutRemoteService = 613 initiateProviderSessionsWithActiveContainers( 614 session, 615 getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); 616 617 List<ProviderSession> sessionsWithRemoteService = 618 initiateProviderSessions( 619 session, 620 optionsThatDoNotRequireActiveCredentials.stream() 621 .map(CredentialOption::getType) 622 .collect(Collectors.toList())); 623 624 Set<ProviderSession> all = new LinkedHashSet<>(); 625 all.addAll(sessionsWithRemoteService); 626 all.addAll(sessionsWithoutRemoteService); 627 628 providerSessions = new ArrayList<>(all); 629 } else { 630 // Initiate all provider sessions 631 providerSessions = 632 initiateProviderSessions( 633 session, 634 request.getCredentialOptions().stream() 635 .map(CredentialOption::getType) 636 .collect(Collectors.toList())); 637 } 638 639 finalizeAndEmitInitialPhaseMetric(session); 640 // TODO(b/271135048) - May still be worth emitting in the empty cases above. 641 return providerSessions; 642 } 643 invokeProviderSessions(List<ProviderSession> providerSessions)644 private void invokeProviderSessions(List<ProviderSession> providerSessions) { 645 providerSessions.forEach(ProviderSession::invokeSession); 646 } 647 648 @Override executeCreateCredential( CreateCredentialRequest request, ICreateCredentialCallback callback, String callingPackage)649 public ICancellationSignal executeCreateCredential( 650 CreateCredentialRequest request, 651 ICreateCredentialCallback callback, 652 String callingPackage) { 653 final long timestampBegan = System.nanoTime(); 654 Slog.i(TAG, "starting executeCreateCredential with callingPackage: " 655 + callingPackage); 656 ICancellationSignal cancelTransport = CancellationSignal.createTransport(); 657 658 if (request.getOrigin() != null) { 659 // Check privileged permissions 660 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); 661 } 662 663 final int userId = UserHandle.getCallingUserId(); 664 final int callingUid = Binder.getCallingUid(); 665 enforceCallingPackage(callingPackage, callingUid); 666 667 // New request session, scoped for this request only. 668 final CreateRequestSession session = 669 new CreateRequestSession( 670 getContext(), 671 mSessionManager, 672 mLock, 673 userId, 674 callingUid, 675 request, 676 callback, 677 constructCallingAppInfo(callingPackage, userId, request.getOrigin()), 678 getEnabledProvidersForUser(userId), 679 getPrimaryProvidersForUserId(getContext(), userId), 680 CancellationSignal.fromTransport(cancelTransport), 681 timestampBegan); 682 addSessionLocked(userId, session); 683 684 processCreateCredential(request, callback, session); 685 return cancelTransport; 686 } 687 processCreateCredential( CreateCredentialRequest request, ICreateCredentialCallback callback, CreateRequestSession session)688 private void processCreateCredential( 689 CreateCredentialRequest request, 690 ICreateCredentialCallback callback, 691 CreateRequestSession session) { 692 // Initiate all provider sessions 693 List<ProviderSession> providerSessions = 694 initiateProviderSessions(session, List.of(request.getType())); 695 696 if (providerSessions.isEmpty()) { 697 try { 698 callback.onError( 699 CreateCredentialException.TYPE_NO_CREATE_OPTIONS, 700 "No create options available."); 701 } catch (RemoteException e) { 702 Slog.e( 703 TAG, 704 "Issue invoking onError on ICreateCredentialCallback " 705 + "callback: ", e); 706 } 707 } 708 709 finalizeAndEmitInitialPhaseMetric(session); 710 // Iterate over all provider sessions and invoke the request 711 providerSessions.forEach(ProviderSession::invokeSession); 712 } 713 finalizeAndEmitInitialPhaseMetric(RequestSession session)714 private void finalizeAndEmitInitialPhaseMetric(RequestSession session) { 715 try { 716 var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric(); 717 initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime()); 718 MetricUtilities.logApiCalledInitialPhase(initMetric, 719 session.mRequestSessionMetric.returnIncrementSequence()); 720 } catch (Exception e) { 721 Slog.i(TAG, "Unexpected error during metric logging: ", e); 722 } 723 } 724 725 @Override setEnabledProviders( List<String> primaryProviders, List<String> providers, int userId, ISetEnabledProvidersCallback callback)726 public void setEnabledProviders( 727 List<String> primaryProviders, List<String> providers, int userId, 728 ISetEnabledProvidersCallback callback) { 729 final int callingUid = Binder.getCallingUid(); 730 if (!hasWriteSecureSettingsPermission()) { 731 try { 732 MetricUtilities.logApiCalledSimpleV2( 733 ApiName.SET_ENABLED_PROVIDERS, 734 ApiStatus.FAILURE, callingUid); 735 callback.onError( 736 PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR); 737 } catch (RemoteException e) { 738 MetricUtilities.logApiCalledSimpleV2( 739 ApiName.SET_ENABLED_PROVIDERS, 740 ApiStatus.FAILURE, callingUid); 741 Slog.e(TAG, "Issue with invoking response: ", e); 742 } 743 return; 744 } 745 746 userId = 747 ActivityManager.handleIncomingUser( 748 Binder.getCallingPid(), 749 Binder.getCallingUid(), 750 userId, 751 false, 752 false, 753 "setEnabledProviders", 754 null); 755 756 Set<String> enableProvider = new HashSet<>(providers); 757 enableProvider.addAll(primaryProviders); 758 759 boolean writeEnabledStatus = 760 Settings.Secure.putStringForUser(getContext().getContentResolver(), 761 Settings.Secure.CREDENTIAL_SERVICE, 762 String.join(":", enableProvider), 763 userId); 764 765 boolean writePrimaryStatus = 766 Settings.Secure.putStringForUser(getContext().getContentResolver(), 767 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, 768 String.join(":", primaryProviders), 769 userId); 770 771 if (!writeEnabledStatus || !writePrimaryStatus) { 772 Slog.e(TAG, "Failed to store setting containing enabled or primary providers"); 773 try { 774 MetricUtilities.logApiCalledSimpleV2( 775 ApiName.SET_ENABLED_PROVIDERS, 776 ApiStatus.FAILURE, callingUid); 777 callback.onError( 778 "failed_setting_store", 779 "Failed to store setting containing enabled or primary providers"); 780 } catch (RemoteException e) { 781 MetricUtilities.logApiCalledSimpleV2( 782 ApiName.SET_ENABLED_PROVIDERS, 783 ApiStatus.FAILURE, callingUid); 784 Slog.e(TAG, "Issue with invoking error response: ", e); 785 return; 786 } 787 } 788 789 // Call the callback. 790 try { 791 MetricUtilities.logApiCalledSimpleV2( 792 ApiName.SET_ENABLED_PROVIDERS, 793 ApiStatus.SUCCESS, callingUid); 794 callback.onResponse(); 795 } catch (RemoteException e) { 796 MetricUtilities.logApiCalledSimpleV2( 797 ApiName.SET_ENABLED_PROVIDERS, 798 ApiStatus.FAILURE, callingUid); 799 Slog.e(TAG, "Issue with invoking response: ", e); 800 // TODO: Propagate failure 801 } 802 } 803 804 @Override isEnabledCredentialProviderService( ComponentName componentName, String callingPackage)805 public boolean isEnabledCredentialProviderService( 806 ComponentName componentName, String callingPackage) { 807 Slog.i(TAG, "isEnabledCredentialProviderService with componentName: " 808 + componentName.flattenToString()); 809 810 // TODO(253157366): Check additional set of services. 811 final int userId = UserHandle.getCallingUserId(); 812 final int callingUid = Binder.getCallingUid(); 813 enforceCallingPackage(callingPackage, callingUid); 814 synchronized (mLock) { 815 final List<CredentialManagerServiceImpl> services = 816 getServiceListForUserLocked(userId); 817 for (CredentialManagerServiceImpl s : services) { 818 final ComponentName serviceComponentName = s.getServiceComponentName(); 819 820 if (serviceComponentName.equals(componentName)) { 821 if (!s.getServicePackageName().equals(callingPackage)) { 822 // The component name and the package name do not match. 823 MetricUtilities.logApiCalledSimpleV2( 824 ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, 825 ApiStatus.FAILURE, callingUid); 826 Slog.w( 827 TAG, 828 "isEnabledCredentialProviderService: Component name does " 829 + "not match package name."); 830 return false; 831 } 832 MetricUtilities.logApiCalledSimpleV2( 833 ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, 834 ApiStatus.SUCCESS, callingUid); 835 return true; 836 } 837 } 838 } 839 840 return false; 841 } 842 843 @Override getCredentialProviderServices( int userId, int providerFilter)844 public List<CredentialProviderInfo> getCredentialProviderServices( 845 int userId, int providerFilter) { 846 verifyGetProvidersPermission(); 847 final int callingUid = Binder.getCallingUid(); 848 MetricUtilities.logApiCalledSimpleV2( 849 ApiName.GET_CREDENTIAL_PROVIDER_SERVICES, 850 ApiStatus.SUCCESS, callingUid); 851 return CredentialProviderInfoFactory 852 .getCredentialProviderServices( 853 mContext, userId, providerFilter, getEnabledProvidersForUser(userId), 854 getPrimaryProvidersForUserId(mContext, userId)); 855 856 } 857 858 @Override getCredentialProviderServicesForTesting( int providerFilter)859 public List<CredentialProviderInfo> getCredentialProviderServicesForTesting( 860 int providerFilter) { 861 verifyGetProvidersPermission(); 862 863 final int userId = UserHandle.getCallingUserId(); 864 return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting( 865 mContext, userId, providerFilter, getEnabledProvidersForUser(userId), 866 getPrimaryProvidersForUserId(mContext, userId)); 867 } 868 869 @Override isServiceEnabled()870 public boolean isServiceEnabled() { 871 final long origId = Binder.clearCallingIdentity(); 872 try { 873 return DeviceConfig.getBoolean( 874 DeviceConfig.NAMESPACE_CREDENTIAL, 875 DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER, 876 true); 877 } finally { 878 Binder.restoreCallingIdentity(origId); 879 } 880 } 881 getEnabledProvidersForUser(int userId)882 private Set<ComponentName> getEnabledProvidersForUser(int userId) { 883 final int resolvedUserId = ActivityManager.handleIncomingUser( 884 Binder.getCallingPid(), Binder.getCallingUid(), 885 userId, false, false, 886 "getEnabledProvidersForUser", null); 887 888 Set<ComponentName> enabledProviders = new HashSet<>(); 889 String directValue = Settings.Secure.getStringForUser( 890 mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, resolvedUserId); 891 892 if (!TextUtils.isEmpty(directValue)) { 893 String[] components = directValue.split(":"); 894 for (String componentString : components) { 895 ComponentName component = ComponentName.unflattenFromString(componentString); 896 if (component != null) { 897 enabledProviders.add(component); 898 } 899 } 900 } 901 902 return enabledProviders; 903 } 904 905 @Override clearCredentialState( ClearCredentialStateRequest request, IClearCredentialStateCallback callback, String callingPackage)906 public ICancellationSignal clearCredentialState( 907 ClearCredentialStateRequest request, 908 IClearCredentialStateCallback callback, 909 String callingPackage) { 910 final long timestampBegan = System.nanoTime(); 911 Slog.i(TAG, "starting clearCredentialState with callingPackage: " 912 + callingPackage); 913 final int userId = UserHandle.getCallingUserId(); 914 int callingUid = Binder.getCallingUid(); 915 enforceCallingPackage(callingPackage, callingUid); 916 917 // TODO : Implement cancellation 918 ICancellationSignal cancelTransport = CancellationSignal.createTransport(); 919 920 // New request session, scoped for this request only. 921 final ClearRequestSession session = 922 new ClearRequestSession( 923 getContext(), 924 mSessionManager, 925 mLock, 926 userId, 927 callingUid, 928 callback, 929 request, 930 constructCallingAppInfo(callingPackage, userId, null), 931 getEnabledProvidersForUser(userId), 932 CancellationSignal.fromTransport(cancelTransport), 933 timestampBegan); 934 addSessionLocked(userId, session); 935 936 // Initiate all provider sessions 937 // TODO: Determine if provider needs to have clear capability in their manifest 938 List<ProviderSession> providerSessions = initiateProviderSessions(session, List.of()); 939 940 if (providerSessions.isEmpty()) { 941 try { 942 // TODO("Replace with properly defined error type") 943 callback.onError("UNKNOWN", "No credentials available on " 944 + "this device"); 945 } catch (RemoteException e) { 946 Slog.e( 947 TAG, 948 "Issue invoking onError on IClearCredentialStateCallback " 949 + "callback: ", e); 950 } 951 } 952 953 finalizeAndEmitInitialPhaseMetric(session); 954 955 // Iterate over all provider sessions and invoke the request 956 providerSessions.forEach(ProviderSession::invokeSession); 957 return cancelTransport; 958 } 959 960 @Override registerCredentialDescription( RegisterCredentialDescriptionRequest request, String callingPackage)961 public void registerCredentialDescription( 962 RegisterCredentialDescriptionRequest request, String callingPackage) 963 throws IllegalArgumentException, NonCredentialProviderCallerException { 964 Slog.i(TAG, "registerCredentialDescription with callingPackage: " + callingPackage); 965 966 if (!isCredentialDescriptionApiEnabled()) { 967 throw new UnsupportedOperationException("Feature not supported"); 968 } 969 970 enforceCallingPackage(callingPackage, Binder.getCallingUid()); 971 972 CredentialDescriptionRegistry session = 973 CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); 974 975 session.executeRegisterRequest(request, callingPackage); 976 } 977 978 @Override unregisterCredentialDescription( UnregisterCredentialDescriptionRequest request, String callingPackage)979 public void unregisterCredentialDescription( 980 UnregisterCredentialDescriptionRequest request, String callingPackage) 981 throws IllegalArgumentException { 982 Slog.i(TAG, "unregisterCredentialDescription with callingPackage: " 983 + callingPackage); 984 985 986 if (!isCredentialDescriptionApiEnabled()) { 987 throw new UnsupportedOperationException("Feature not supported"); 988 } 989 990 enforceCallingPackage(callingPackage, Binder.getCallingUid()); 991 992 CredentialDescriptionRegistry session = 993 CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); 994 995 session.executeUnregisterRequest(request, callingPackage); 996 } 997 } 998 validateGetCredentialRequest(GetCredentialRequest request)999 private void validateGetCredentialRequest(GetCredentialRequest request) { 1000 if (request.getOrigin() != null) { 1001 // Check privileged permissions 1002 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); 1003 } 1004 enforcePermissionForAllowedProviders(request); 1005 } 1006 enforcePermissionForAllowedProviders(GetCredentialRequest request)1007 private void enforcePermissionForAllowedProviders(GetCredentialRequest request) { 1008 boolean containsAllowedProviders = request.getCredentialOptions() 1009 .stream() 1010 .anyMatch(option -> option.getAllowedProviders() != null 1011 && !option.getAllowedProviders().isEmpty()); 1012 if (containsAllowedProviders) { 1013 mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS, 1014 null); 1015 } 1016 } 1017 addSessionLocked(@serIdInt int userId, RequestSession requestSession)1018 private void addSessionLocked(@UserIdInt int userId, 1019 RequestSession requestSession) { 1020 synchronized (mLock) { 1021 mSessionManager.addSession(userId, requestSession.mRequestId, requestSession); 1022 } 1023 } 1024 enforceCallingPackage(String callingPackage, int callingUid)1025 private void enforceCallingPackage(String callingPackage, int callingUid) { 1026 int packageUid; 1027 PackageManager pm = mContext.createContextAsUser( 1028 UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager(); 1029 try { 1030 packageUid = pm.getPackageUid(callingPackage, 1031 PackageManager.PackageInfoFlags.of(0)); 1032 } catch (PackageManager.NameNotFoundException e) { 1033 throw new SecurityException(callingPackage + " not found"); 1034 } 1035 if (packageUid != callingUid) { 1036 throw new SecurityException(callingPackage + " does not belong to uid " + callingUid); 1037 } 1038 } 1039 1040 private class SessionManager implements RequestSession.SessionLifetime { 1041 @Override 1042 @GuardedBy("mLock") onFinishRequestSession(@serIdInt int userId, IBinder token)1043 public void onFinishRequestSession(@UserIdInt int userId, IBinder token) { 1044 if (mRequestSessions.get(userId) != null) { 1045 mRequestSessions.get(userId).remove(token); 1046 } 1047 } 1048 1049 @GuardedBy("mLock") addSession(int userId, IBinder token, RequestSession requestSession)1050 public void addSession(int userId, IBinder token, RequestSession requestSession) { 1051 if (mRequestSessions.get(userId) == null) { 1052 mRequestSessions.put(userId, new HashMap<>()); 1053 } 1054 mRequestSessions.get(userId).put(token, requestSession); 1055 } 1056 } 1057 } 1058