/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.geoserver.security.impl.GeoServerUser;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.StringUtils;
/**
* Uses the property file <code>$GEOSERVER_DATA_DIR/security/authkey.properties</code> as the source
* for unique user identifiers. The file format is:
* <ul>
* <li>userkey1=username1</li>
* <li>userkey2=username2</li>
* <li>...</li>
* </ul>
*
* The file will be automatically reloaded when modified
*
* @author Andrea Aime - GeoSolutions
*/
public class PropertyAuthenticationKeyMapper extends AbstractAuthenticationKeyMapper {
/**
* Name of the file used to store the authentication keys
*/
public static final String AUTHKEYS_FILE = "authkeys.properties";
PropertyFileWatcher fileWatcher;
Properties authKeyProps;
public boolean supportsReadOnlyUserGroupService() {
return true;
}
@Override
synchronized public GeoServerUser getUser(String key) throws IOException {
checkProperties();
if (authKeyProps==null) {
synchronize();
}
if (fileWatcher.isStale()) // reload if necessary
authKeyProps=fileWatcher.getProperties();
String userName = authKeyProps.getProperty(key);
if (StringUtils.hasLength(userName)==false) {
LOGGER.warning("Cannot find user for auth key: "+key);
return null;
}
GeoServerUser theUser=null;
try {
theUser= (GeoServerUser)
getUserGroupService().loadUserByUsername(userName);
} catch (UsernameNotFoundException ex) {
LOGGER.warning("Cannot find user: "+userName+" in user/group service: " +getUserGroupServiceName());
return null;
}
if (theUser.isEnabled()==false) {
LOGGER.info("Found user "+theUser.getUsername()+ " for key " + key +
", but this user is disabled");
return null;
}
return theUser;
}
@Override
protected void checkProperties() throws IOException {
super.checkProperties();
}
@Override
synchronized public int synchronize() throws IOException {
checkProperties();
File propFile=new File(getSecurityManager().getUserGroupRoot(),getUserGroupServiceName());
propFile=new File(propFile,AUTHKEYS_FILE);
File backupFile=new File(getSecurityManager().getUserGroupRoot(),getUserGroupServiceName());
backupFile=new File(backupFile,AUTHKEYS_FILE+".backup");
// check if the previous synchronize failed
if (backupFile.exists())
throw new IOException("The file: "+backupFile.getCanonicalPath() + " has to be removed first");
authKeyProps=new Properties();
Properties oldProps=new Properties();
// check if property file exists and reload
if (propFile.exists()) {
FileUtils.copyFile(propFile, backupFile);
FileInputStream inputFile = new FileInputStream(backupFile);
try {
oldProps.load(inputFile);
} finally {
inputFile.close();
}
}
Map<Object,Object> reverseMap=new HashMap<Object,Object>();
for ( Entry<Object,Object> entry :oldProps.entrySet()) {
reverseMap.put(entry.getValue(),entry.getKey());
}
GeoServerUserGroupService service = getUserGroupService();
int counter=0;
for (GeoServerUser user : service.getUsers()) {
if (reverseMap.containsKey(user.getUsername())) {
authKeyProps.put(reverseMap.get(user.getUsername()),user.getUsername());
} else {
authKeyProps.put(createAuthKey(), user.getUsername());
counter++;
}
}
FileOutputStream outputFile = new FileOutputStream(propFile, false);
try {
authKeyProps.store(outputFile, "Format is authkey=username");
} finally {
outputFile.close();
}
if (backupFile.exists())
backupFile.delete();
fileWatcher=new PropertyFileWatcher(propFile);
return counter;
}
}