All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.appengine.repackaged.com.google.api.client.util.store.FileDataStoreFactory Maven / Gradle / Ivy

Go to download

API for Google App Engine standard environment with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.27
Show newest version
/*
 * Copyright (c) 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.api.client.util.store;

import com.google.api.client.util.IOUtils;
import com.google.api.client.util.Maps;
import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryPermission;
import java.nio.file.attribute.AclEntryType;
import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.FileOwnerAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

/**
 * Thread-safe file implementation of a credential store.
 *
 * 

For security purposes, the file's permissions are set such that the file is only accessible by * the file's owner. * *

Note: this class is not compatible with Android lower than API level 26 (Oreo). For an * implementation compatible with Android < 26, please use * com.google.api.client.extensions.android.util.store.FileDataStoreFactory which is provided by * com.google.http-client:google-http-client-android. * * @since 1.16 * @author Yaniv Inbar */ public class FileDataStoreFactory extends AbstractDataStoreFactory { private static final boolean IS_WINDOWS = StandardSystemProperty.OS_NAME.value().toLowerCase(Locale.ENGLISH).startsWith("windows"); /** Directory to store data. */ private final File dataDirectory; /** @param dataDirectory data directory */ public FileDataStoreFactory(File dataDirectory) throws IOException { dataDirectory = dataDirectory.getCanonicalFile(); // error if it is a symbolic link if (IOUtils.isSymbolicLink(dataDirectory)) { throw new IOException("unable to use a symbolic link: " + dataDirectory); } // create parent directory (if necessary) if (!dataDirectory.exists() && !dataDirectory.mkdirs()) { throw new IOException("unable to create directory: " + dataDirectory); } this.dataDirectory = dataDirectory; if (IS_WINDOWS) { setPermissionsToOwnerOnlyWindows(dataDirectory); } else { setPermissionsToOwnerOnly(dataDirectory); } } /** Returns the data directory. */ public final File getDataDirectory() { return dataDirectory; } @Override protected DataStore createDataStore(String id) throws IOException { return new FileDataStore(this, dataDirectory, id); } /** * File data store that inherits from the abstract memory data store because the key-value pairs * are stored in a memory cache, and saved in the file (see {@link #save()} when changing values. * * @param serializable type of the mapped value */ static class FileDataStore extends AbstractMemoryDataStore { /** File to store data. */ private final File dataFile; FileDataStore(FileDataStoreFactory dataStore, File dataDirectory, String id) throws IOException { super(dataStore, id); this.dataFile = new File(dataDirectory, id); // error if it is a symbolic link if (IOUtils.isSymbolicLink(dataFile)) { throw new IOException("unable to use a symbolic link: " + dataFile); } // create new file (if necessary) if (dataFile.createNewFile()) { keyValueMap = Maps.newHashMap(); // save the credentials to create a new file save(); } else { // load credentials from existing file keyValueMap = IOUtils.deserialize(new FileInputStream(dataFile)); } } @Override public void save() throws IOException { IOUtils.serialize(keyValueMap, new FileOutputStream(dataFile)); } @Override public FileDataStoreFactory getDataStoreFactory() { return (FileDataStoreFactory) super.getDataStoreFactory(); } } /** * Attempts to set the given file's permissions such that it can only be read, written, and * executed by the file's owner. * * @param file the file's permissions to modify * @throws IOException if the permissions can't be set */ private static void setPermissionsToOwnerOnly(File file) throws IOException { Set permissions = new HashSet(); permissions.add(PosixFilePermission.OWNER_READ); permissions.add(PosixFilePermission.OWNER_WRITE); permissions.add(PosixFilePermission.OWNER_EXECUTE); try { Files.setPosixFilePermissions(Paths.get(file.getAbsolutePath()), permissions); } catch (RuntimeException exception) { throw new IOException("Unable to set permissions for " + file, exception); } } private static void setPermissionsToOwnerOnlyWindows(File file) throws IOException { Path path = Paths.get(file.getAbsolutePath()); FileOwnerAttributeView fileAttributeView = Files.getFileAttributeView(path, FileOwnerAttributeView.class); UserPrincipal owner = fileAttributeView.getOwner(); // get view AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class); // All available entries Set permissions = ImmutableSet.of( AclEntryPermission.APPEND_DATA, AclEntryPermission.DELETE, AclEntryPermission.DELETE_CHILD, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.READ_NAMED_ATTRS, AclEntryPermission.SYNCHRONIZE, AclEntryPermission.WRITE_ACL, AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.WRITE_NAMED_ATTRS, AclEntryPermission.WRITE_OWNER); // create ACL to give owner everything AclEntry entry = AclEntry.newBuilder() .setType(AclEntryType.ALLOW) .setPrincipal(owner) .setPermissions(permissions) .build(); // Overwrite the ACL with only this permission try { view.setAcl(ImmutableList.of(entry)); } catch (SecurityException ex) { throw new IOException("Unable to set permissions for " + file, ex); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy