Continue with security update

This commit is contained in:
Admin
2017-03-23 16:36:25 -05:00
parent ddee3a42a9
commit b508a8a16a
12 changed files with 329 additions and 47 deletions

View File

@@ -0,0 +1,25 @@
package com.bwssystems.HABridge;
import spark.Request;
public abstract class AuthFramework {
private static final String USER_SESSION_ID = "user";
public AuthFramework() {
// TODO Auto-generated constructor stub
}
private void addAuthenticatedUser(Request request, User u) {
request.session().attribute(USER_SESSION_ID, u);
}
private void removeAuthenticatedUser(Request request) {
request.session().removeAttribute(USER_SESSION_ID);
}
private User getAuthenticatedUser(Request request) {
return request.session().attribute(USER_SESSION_ID);
}
}

View File

@@ -25,10 +25,12 @@ public class BridgeSecurity {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
};
private BridgeSecurityDescriptor securityDescriptor;
private boolean settingsChanged;
public BridgeSecurity(char[] theKey, String theData) {
habridgeKey = theKey;
securityDescriptor = null;
settingsChanged = false;
String anError = null;
if(theData != null && !theData.isEmpty()) {
try {
@@ -56,20 +58,28 @@ public class BridgeSecurity {
return securityDescriptor.isUseLinkButton();
}
public void setPassword(String aPassword) throws IOException {
if(aPassword != null) {
securityDescriptor.setUiPassword(String.valueOf(base64Decode(aPassword)));
securityDescriptor.setPasswordSet(true);
} else {
securityDescriptor.setUiPassword(null);
securityDescriptor.setPasswordSet(false);
public String setPassword(User aUser) throws IOException {
String error = null;
if(aUser != null) {
error = aUser.validate();
if(error == null) {
User theUser = securityDescriptor.getUsers().get(aUser.getUsername());
if(theUser != null) {
theUser.setPassword(aUser.getPassword());
theUser.setPassword2(null);
settingsChanged = true;
}
}
}
securityDescriptor.setSettingsChanged(true);
else
error = "invalid user object given";
return error;
}
public void setExecGarden(String theGarden) {
securityDescriptor.setExecGarden(theGarden);
securityDescriptor.setSettingsChanged(true);
settingsChanged = true;
}
public String getExecGarden() {
@@ -77,22 +87,43 @@ public class BridgeSecurity {
}
public void setUseLinkButton(boolean useThis) {
securityDescriptor.setUseLinkButton(useThis);
securityDescriptor.setSettingsChanged(true);
settingsChanged = true;
}
public boolean validatePassword(String targetPassword) throws IOException {
if(securityDescriptor.isPasswordSet()) {
if(securityDescriptor.getUiPassword().equals(String.valueOf(base64Decode(targetPassword))))
public SecurityInfo getSecurityInfo() {
SecurityInfo theInfo = new SecurityInfo();
theInfo.setExecGarden(getExecGarden());
theInfo.setUseLinkButton(isUseLinkButton());
theInfo.setSecure(isSecure());
return theInfo;
}
public boolean validatePassword(User targetUser) throws IOException {
if(targetUser != null) {
User theUser = securityDescriptor.getUsers().get(targetUser.getUsername());
if(theUser.getPassword() != null) {
theUser.setPassword2(targetUser.getPassword());
if(theUser.validatePassword()) {
theUser.setPassword2(null);
return true;
}
} else {
log.warn("validating password when password is not set....");
return true;
} else {
log.warn("validating password when password is not set....");
return true;
}
}
return false;
}
public boolean isSecure() {
return securityDescriptor.isPasswordSet();
return securityDescriptor.isSecure();
}
public boolean isSettingsChanged() {
return settingsChanged;
}
public void setSettingsChanged(boolean settingsChanged) {
this.settingsChanged = settingsChanged;
}
private String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {

View File

@@ -1,33 +1,24 @@
package com.bwssystems.HABridge;
import java.util.Map;
public class BridgeSecurityDescriptor {
private String uiPassword;
private boolean passwordSet;
private Map<String, User> users;
private boolean useLinkButton;
private String execGarden;
private boolean settingsChanged;
private boolean secureHueApi;
public BridgeSecurityDescriptor() {
super();
this.setUiPassword(null);
this.setPasswordSet(false);
this.setUseLinkButton(false);
}
public String getUiPassword() {
return uiPassword;
public Map<String, User> getUsers() {
return users;
}
public void setUiPassword(String uiPassword) {
this.uiPassword = uiPassword;
}
public boolean isPasswordSet() {
return passwordSet;
}
public void setPasswordSet(boolean passwordSet) {
this.passwordSet = passwordSet;
public void setUsers(Map<String, User> users) {
this.users = users;
}
public boolean isUseLinkButton() {
@@ -46,11 +37,26 @@ public class BridgeSecurityDescriptor {
this.execGarden = execGarden;
}
public boolean isSettingsChanged() {
return settingsChanged;
public boolean isSecureHueApi() {
return secureHueApi;
}
public void setSettingsChanged(boolean settingsChanged) {
this.settingsChanged = settingsChanged;
public void setSecureHueApi(boolean secureHueApi) {
this.secureHueApi = secureHueApi;
}
public boolean isSecure() {
boolean secureFlag = false;
if(users != null && !users.isEmpty()) {
for (Map.Entry<String, User> entry : users.entrySet())
{
if(entry.getValue().getPassword() != null && !entry.getValue().getPassword().isEmpty()) {
secureFlag = true;
break;
}
}
}
return secureFlag;
}
}

View File

@@ -1,6 +1,7 @@
package com.bwssystems.HABridge;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
@@ -10,6 +11,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.PosixFilePermission;
import java.security.GeneralSecurityException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
@@ -213,6 +215,18 @@ public class BridgeSettings extends BackupHandler {
log.debug("Save HA Bridge settings.");
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
JsonTransformer aRenderer = new JsonTransformer();
if(bridgeSecurity.isSettingsChanged()) {
try {
newBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bridgeSecurity.setSettingsChanged(false);
}
String jsonValue = aRenderer.render(newBridgeSettings);
configWriter(jsonValue, configPath);
_loadConfig(configPath);

View File

@@ -0,0 +1,33 @@
package com.bwssystems.HABridge;
public class SecurityInfo {
private boolean useLinkButton;
private String execGarden;
private boolean seucreHueApi;
private boolean isSecure;
public boolean isUseLinkButton() {
return useLinkButton;
}
public void setUseLinkButton(boolean useLinkButton) {
this.useLinkButton = useLinkButton;
}
public String getExecGarden() {
return execGarden;
}
public void setExecGarden(String execGarden) {
this.execGarden = execGarden;
}
public boolean isSeucreHueApi() {
return seucreHueApi;
}
public void setSeucreHueApi(boolean seucreHueApi) {
this.seucreHueApi = seucreHueApi;
}
public boolean isSecure() {
return isSecure;
}
public void setSecure(boolean isSecure) {
this.isSecure = isSecure;
}
}

View File

@@ -31,7 +31,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.read.CyclicBufferAppender;
public class SystemControl {
public class SystemControl extends AuthFramework {
private static final Logger log = LoggerFactory.getLogger(SystemControl.class);
public static final String CYCLIC_BUFFER_APPENDER_NAME = "CYCLIC";
private LoggerContext lc;
@@ -110,6 +110,13 @@ public class SystemControl {
return theLogServiceMgr.getConfiguredLoggers();
}, new JsonTransformer());
// http://ip_address:port/system/securityinfo gets the security info for the bridge
get (SYSTEM_CONTEXT + "/securityinfo", "application/json", (request, response) -> {
log.debug("Get security info");
response.status(200);
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
}, new JsonTransformer());
// http://ip_address:port/system/presslinkbutton CORS request
options(SYSTEM_CONTEXT + "/presslinkbutton", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
@@ -128,6 +135,55 @@ public class SystemControl {
return null;
}, new JsonTransformer());
// http://ip_address:port/system/setpassword CORS request
options(SYSTEM_CONTEXT + "/setpassword", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/system/setpassword which sets a password for a given user
post(SYSTEM_CONTEXT + "/setpassword", "application/json", (request, response) -> {
log.debug("setpassword....");
return null;
}, new JsonTransformer());
// http://ip_address:port/system/changesecurityinfo CORS request
options(SYSTEM_CONTEXT + "/changesecurityinfo", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/system/changesecurityinfo which sets the security settings other than passwords and users
post(SYSTEM_CONTEXT + "/changesecurityinfo", "application/json", (request, response) -> {
log.debug("changesecurityinfo....");
SecurityInfo theInfo = new Gson().fromJson(request.body(), SecurityInfo.class);
if(theInfo.getExecGarden() != null)
bridgeSettings.getBridgeSecurity().setExecGarden(theInfo.getExecGarden());
bridgeSettings.getBridgeSecurity().setUseLinkButton(theInfo.isUseLinkButton());
return null;
}, new JsonTransformer());
// http://ip_address:port/system/login CORS request
options(SYSTEM_CONTEXT + "/login", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/system/login validates the login
post(SYSTEM_CONTEXT + "/login", "application/json", (request, response) -> {
log.debug("login....");
return null;
}, new JsonTransformer());
// http://ip_address:port/system/logmgmt/update CORS request
options(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);

View File

@@ -0,0 +1,65 @@
package com.bwssystems.HABridge;
import spark.utils.StringUtils;
public class User {
private int id;
private String username;
private String password;
private String password2;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword2() {
return password2;
}
public void setPassword2(String password2) {
this.password2 = password2;
}
public String validate() {
String error = null;
if(StringUtils.isEmpty(username)) {
error = "You have to enter a username";
} else if(StringUtils.isEmpty(password)) {
error = "You have to enter a password";
} else if(!password.equals(password2)) {
error = "The two passwords do not match";
}
return error;
}
public boolean validatePassword() {
if(password != null && password2 != null)
return password.equals(password2);
return false;
}
}

View File

@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.AuthFramework;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
@@ -40,7 +41,7 @@ import java.util.Map;
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
*/
public class HueMulator {
public class HueMulator extends AuthFramework {
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
private static final String HUE_CONTEXT = "/api";