Line data Source code
1 : // Copyright (C) 2013 The Android Open Source Project 2 : // 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 : package com.google.gerrit.server.securestore; 16 : 17 : import com.google.gerrit.common.FileUtil; 18 : import com.google.gerrit.common.Nullable; 19 : import com.google.gerrit.server.config.SitePaths; 20 : import com.google.inject.Inject; 21 : import com.google.inject.ProvisionException; 22 : import com.google.inject.Singleton; 23 : import java.io.File; 24 : import java.io.IOException; 25 : import java.util.ArrayList; 26 : import java.util.HashMap; 27 : import java.util.List; 28 : import java.util.Map; 29 : import org.eclipse.jgit.errors.ConfigInvalidException; 30 : import org.eclipse.jgit.internal.storage.file.LockFile; 31 : import org.eclipse.jgit.lib.Constants; 32 : import org.eclipse.jgit.storage.file.FileBasedConfig; 33 : import org.eclipse.jgit.util.FS; 34 : 35 : @Singleton 36 : public class DefaultSecureStore extends SecureStore { 37 : private final FileBasedConfig sec; 38 : private final Map<String, FileBasedConfig> pluginSec; 39 : private final SitePaths site; 40 : 41 : @Inject 42 150 : DefaultSecureStore(SitePaths site) { 43 150 : this.site = site; 44 150 : sec = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED); 45 : try { 46 150 : sec.load(); 47 0 : } catch (IOException | ConfigInvalidException e) { 48 0 : throw new RuntimeException("Cannot load secure.config", e); 49 150 : } 50 150 : this.pluginSec = new HashMap<>(); 51 150 : } 52 : 53 : @Override 54 : public String[] getList(String section, String subsection, String name) { 55 16 : return sec.getStringList(section, subsection, name); 56 : } 57 : 58 : @Nullable 59 : @Override 60 : public synchronized String[] getListForPlugin( 61 : String pluginName, String section, String subsection, String name) { 62 1 : FileBasedConfig cfg = null; 63 1 : if (pluginSec.containsKey(pluginName)) { 64 0 : cfg = pluginSec.get(pluginName); 65 : } else { 66 1 : String filename = pluginName + ".secure.config"; 67 1 : File pluginConfigFile = site.etc_dir.resolve(filename).toFile(); 68 1 : if (pluginConfigFile.exists()) { 69 0 : cfg = new FileBasedConfig(pluginConfigFile, FS.DETECTED); 70 : try { 71 0 : cfg.load(); 72 0 : pluginSec.put(pluginName, cfg); 73 0 : } catch (IOException | ConfigInvalidException e) { 74 0 : throw new RuntimeException("Cannot load " + filename, e); 75 0 : } 76 : } 77 : } 78 1 : return cfg != null ? cfg.getStringList(section, subsection, name) : null; 79 : } 80 : 81 : @Override 82 : public void setList(String section, String subsection, String name, List<String> values) { 83 15 : if (values != null) { 84 15 : sec.setStringList(section, subsection, name, values); 85 : } else { 86 0 : sec.unset(section, subsection, name); 87 : } 88 15 : save(); 89 15 : } 90 : 91 : @Override 92 : public void unset(String section, String subsection, String name) { 93 15 : sec.unset(section, subsection, name); 94 15 : save(); 95 15 : } 96 : 97 : @Override 98 : public Iterable<EntryKey> list() { 99 0 : List<EntryKey> result = new ArrayList<>(); 100 0 : for (String section : sec.getSections()) { 101 0 : for (String subsection : sec.getSubsections(section)) { 102 0 : for (String name : sec.getNames(section, subsection)) { 103 0 : result.add(new EntryKey(section, subsection, name)); 104 0 : } 105 0 : } 106 0 : for (String name : sec.getNames(section)) { 107 0 : result.add(new EntryKey(section, null, name)); 108 0 : } 109 0 : } 110 0 : return result; 111 : } 112 : 113 : @Override 114 : public boolean isOutdated() { 115 0 : return sec.isOutdated(); 116 : } 117 : 118 : @Override 119 : public void reload() { 120 : try { 121 0 : sec.load(); 122 0 : } catch (IOException | ConfigInvalidException e) { 123 0 : throw new ProvisionException("Couldn't reload secure.config", e); 124 0 : } 125 0 : } 126 : 127 : private void save() { 128 : try { 129 15 : saveSecure(sec); 130 0 : } catch (IOException e) { 131 0 : throw new RuntimeException("Cannot save secure.config", e); 132 15 : } 133 15 : } 134 : 135 : private static void saveSecure(FileBasedConfig sec) throws IOException { 136 15 : if (FileUtil.modified(sec)) { 137 15 : final byte[] out = Constants.encode(sec.toText()); 138 15 : final File path = sec.getFile(); 139 15 : final LockFile lf = new LockFile(path); 140 15 : if (!lf.lock()) { 141 0 : throw new IOException("Cannot lock " + path); 142 : } 143 : try { 144 15 : FileUtil.chmod(0600, new File(path.getParentFile(), path.getName() + ".lock")); 145 15 : lf.write(out); 146 15 : if (!lf.commit()) { 147 0 : throw new IOException("Cannot commit write to " + path); 148 : } 149 : } finally { 150 15 : lf.unlock(); 151 : } 152 : } 153 15 : } 154 : }