Home | History | Annotate | Download | only in enterprise
      1 /*
      2  * Copyright (C) 2016 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.providers.contacts.enterprise;
     18 
     19 import android.annotation.NonNull;
     20 import android.app.admin.DevicePolicyManager;
     21 import android.content.Context;
     22 import android.net.Uri;
     23 import android.os.UserHandle;
     24 import android.provider.ContactsContract;
     25 import android.provider.ContactsContract.Directory;
     26 import android.provider.Settings;
     27 import android.util.Log;
     28 
     29 import com.android.providers.contacts.ContactsProvider2;
     30 import com.android.providers.contacts.ProfileAwareUriMatcher;
     31 import com.android.providers.contacts.util.UserUtils;
     32 import com.google.common.annotations.VisibleForTesting;
     33 
     34 import static android.provider.Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH;
     35 
     36 /**
     37  * Digest contacts policy from DevcicePolicyManager and guard enterprise uri
     38  */
     39 public class EnterprisePolicyGuard {
     40     private static final boolean VERBOSE_LOGGING = ContactsProvider2.VERBOSE_LOGGING;
     41     private static final String TAG = ContactsProvider2.TAG;
     42 
     43     private static final ProfileAwareUriMatcher sUriMatcher = ContactsProvider2.sUriMatcher;
     44 
     45     final private Context mContext;
     46     final private DevicePolicyManager mDpm;
     47 
     48     public EnterprisePolicyGuard(Context context) {
     49         mContext = context;
     50         mDpm = context.getSystemService(DevicePolicyManager.class);
     51     }
     52 
     53     /**
     54      * Check if cross profile query is allowed for the given uri
     55      *
     56      * @param uri Uri that we want to check.
     57      * @return True if cross profile query is allowed for this uri
     58      */
     59     public boolean isCrossProfileAllowed(@NonNull Uri uri) {
     60         final int uriCode = sUriMatcher.match(uri);
     61         final UserHandle currentHandle = new UserHandle(UserUtils.getCurrentUserHandle(mContext));
     62         if (uriCode == -1 || currentHandle == null) {
     63             return false;
     64         }
     65 
     66         if (isUriWhitelisted(uriCode)) {
     67             return true;
     68         }
     69 
     70         final boolean isCallerIdEnabled = !mDpm.getCrossProfileCallerIdDisabled(currentHandle);
     71         final boolean isContactsSearchPolicyEnabled =
     72                 !mDpm.getCrossProfileContactsSearchDisabled(currentHandle);
     73         final boolean isBluetoothContactSharingEnabled =
     74                 !mDpm.getBluetoothContactSharingDisabled(currentHandle);
     75         final boolean isContactRemoteSearchUserEnabled = isContactRemoteSearchUserSettingEnabled();
     76 
     77         final String directory = uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
     78 
     79         if (VERBOSE_LOGGING) {
     80             Log.v(TAG, "isCallerIdEnabled: " + isCallerIdEnabled);
     81             Log.v(TAG, "isContactsSearchPolicyEnabled: " + isContactsSearchPolicyEnabled);
     82             Log.v(TAG, "isBluetoothContactSharingEnabled: " + isBluetoothContactSharingEnabled);
     83             Log.v(TAG, "isContactRemoteSearchUserEnabled: " + isContactRemoteSearchUserEnabled);
     84         }
     85 
     86         // If it is a remote directory, it is allowed only when
     87         // (i) The uri supports directory
     88         // (ii) User enables it in settings
     89         if (directory != null) {
     90             final long directoryId = Long.parseLong(directory);
     91             if (Directory.isRemoteDirectoryId(directoryId)
     92                     && !(isCrossProfileDirectorySupported(uri)
     93                     && isContactRemoteSearchUserEnabled)) {
     94                 return false;
     95             }
     96         }
     97 
     98         // If either guard policy allows access, return true.
     99         return (isCallerIdGuarded(uriCode) && isCallerIdEnabled)
    100                 || (isContactsSearchGuarded(uriCode) && isContactsSearchPolicyEnabled)
    101                 || (isBluetoothContactSharing(uriCode) && isBluetoothContactSharingEnabled);
    102     }
    103 
    104     private boolean isUriWhitelisted(int uriCode) {
    105         switch (uriCode) {
    106             case ContactsProvider2.PROFILE_AS_VCARD:
    107             case ContactsProvider2.CONTACTS_AS_VCARD:
    108             case ContactsProvider2.CONTACTS_AS_MULTI_VCARD:
    109                 return true;
    110             default:
    111                 return false;
    112         }
    113     }
    114 
    115     /**
    116      * Check if uri is a cross profile query with directory param supported.
    117      *
    118      * @param uri Uri that we want to check.
    119      * @return True if it is an enterprise uri.
    120      */
    121     @VisibleForTesting
    122     protected boolean isCrossProfileDirectorySupported(@NonNull Uri uri) {
    123         final int uriCode = sUriMatcher.match(uri);
    124         return isDirectorySupported(uriCode);
    125     }
    126 
    127     public boolean isValidEnterpriseUri(@NonNull Uri uri) {
    128         final int uriCode = sUriMatcher.match(uri);
    129         return isValidEnterpriseUri(uriCode);
    130     }
    131 
    132     private static boolean isDirectorySupported(int uriCode) {
    133         switch(uriCode) {
    134             case ContactsProvider2.PHONE_LOOKUP:
    135             case ContactsProvider2.EMAILS_LOOKUP:
    136             case ContactsProvider2.CONTACTS_FILTER:
    137             case ContactsProvider2.PHONES_FILTER:
    138             case ContactsProvider2.CALLABLES_FILTER:
    139             case ContactsProvider2.EMAILS_FILTER:
    140             case ContactsProvider2.DIRECTORY_FILE_ENTERPRISE:
    141                 return true;
    142             default:
    143                 return false;
    144         }
    145     }
    146 
    147     private static boolean isValidEnterpriseUri(int uriCode) {
    148         switch (uriCode) {
    149             case ContactsProvider2.PHONE_LOOKUP_ENTERPRISE:
    150             case ContactsProvider2.EMAILS_LOOKUP_ENTERPRISE:
    151             case ContactsProvider2.CONTACTS_FILTER_ENTERPRISE:
    152             case ContactsProvider2.PHONES_FILTER_ENTERPRISE:
    153             case ContactsProvider2.CALLABLES_FILTER_ENTERPRISE:
    154             case ContactsProvider2.EMAILS_FILTER_ENTERPRISE:
    155             case ContactsProvider2.DIRECTORIES_ENTERPRISE:
    156             case ContactsProvider2.DIRECTORIES_ID_ENTERPRISE:
    157             case ContactsProvider2.DIRECTORY_FILE_ENTERPRISE:
    158                 return true;
    159             default:
    160                 return false;
    161         }
    162     }
    163 
    164     private static boolean isCallerIdGuarded(int uriCode) {
    165         switch(uriCode) {
    166             case ContactsProvider2.DIRECTORIES:
    167             case ContactsProvider2.DIRECTORIES_ID:
    168             case ContactsProvider2.PHONE_LOOKUP:
    169             case ContactsProvider2.EMAILS_LOOKUP:
    170             case ContactsProvider2.CONTACTS_ID_PHOTO:
    171             case ContactsProvider2.CONTACTS_ID_DISPLAY_PHOTO:
    172             case ContactsProvider2.DIRECTORY_FILE_ENTERPRISE:
    173                 return true;
    174             default:
    175                 return false;
    176         }
    177     }
    178 
    179     private static boolean isContactsSearchGuarded(int uriCode) {
    180         switch(uriCode) {
    181             case ContactsProvider2.DIRECTORIES:
    182             case ContactsProvider2.DIRECTORIES_ID:
    183             case ContactsProvider2.CONTACTS_FILTER:
    184             case ContactsProvider2.CALLABLES_FILTER:
    185             case ContactsProvider2.PHONES_FILTER:
    186             case ContactsProvider2.EMAILS_FILTER:
    187             case ContactsProvider2.CONTACTS_ID_PHOTO:
    188             case ContactsProvider2.CONTACTS_ID_DISPLAY_PHOTO:
    189             case ContactsProvider2.DIRECTORY_FILE_ENTERPRISE:
    190                 return true;
    191             default:
    192                 return false;
    193         }
    194     }
    195 
    196     private static boolean isBluetoothContactSharing(int uriCode) {
    197         switch(uriCode) {
    198             case ContactsProvider2.PHONES:
    199             case ContactsProvider2.RAW_CONTACT_ENTITIES:
    200                 return true;
    201             default:
    202                 return false;
    203         }
    204     }
    205 
    206     protected boolean isContactRemoteSearchUserSettingEnabled() {
    207         return Settings.Secure.getInt(
    208                 mContext.getContentResolver(),
    209                 MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0) == 1;
    210     }
    211 }
    212