Mercurial > hg > release > thermostat-0.5
changeset 805:1ba58e849ae8
Add auth and auth to webservice.
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-November/004293.html
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Wed, 28 Nov 2012 12:24:00 +0100 |
parents | d6145521e208 |
children | 68eabdccc9b3 |
files | web/client/src/main/java/com/redhat/thermostat/web/client/WebStorage.java web/client/src/main/java/com/redhat/thermostat/web/client/WebStorageProvider.java web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceLauncher.java web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java web/war/pom.xml web/war/src/main/webapp/WEB-INF/web.xml |
diffstat | 8 files changed, 158 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/WebStorage.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/WebStorage.java Wed Nov 28 12:24:00 2012 +0100 @@ -44,6 +44,8 @@ import java.io.OutputStream; import java.io.Reader; import java.lang.reflect.Array; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -56,7 +58,9 @@ import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; -import org.apache.http.client.HttpClient; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ClientConnectionManager; @@ -164,6 +168,7 @@ @Override public void connect() { try { + initAuthentication(httpClient); ping(); connected = true; fireChanged(ConnectionStatus.CONNECTED); @@ -251,7 +256,9 @@ private Map<Category, Integer> categoryIds; private Gson gson; - private HttpClient httpClient; + private DefaultHttpClient httpClient; + private String username; + private String password; public WebStorage() { categoryIds = new HashMap<>(); @@ -261,6 +268,16 @@ httpClient = client; } + private void initAuthentication(DefaultHttpClient client) throws MalformedURLException { + if (username != null && password != null) { + URL endpointURL = new URL(endpoint); + // TODO: Maybe also limit to realm like 'Thermostat Realm' or such? + AuthScope scope = new AuthScope(endpointURL.getHost(), endpointURL.getPort()); + Credentials creds = new UsernamePasswordCredentials(username, password); + client.getCredentialsProvider().setCredentials(scope, creds); + } + } + private void ping() throws StorageException { post(endpoint + "/ping", (HttpEntity) null).close(); } @@ -458,4 +475,9 @@ this.endpoint = endpoint; } + public void setAuthConfig(String username, String password) { + this.username = username; + this.password = password; + } + }
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/WebStorageProvider.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/WebStorageProvider.java Wed Nov 28 12:24:00 2012 +0100 @@ -1,5 +1,6 @@ package com.redhat.thermostat.web.client; +import com.redhat.thermostat.common.cli.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.StorageProvider; @@ -12,6 +13,10 @@ public Storage createStorage() { WebStorage storage = new WebStorage(); storage.setEndpoint(config.getDBConnectionString()); + if (config instanceof AuthenticationConfiguration) { + AuthenticationConfiguration authConf = (AuthenticationConfiguration) config; + storage.setAuthConfig(authConf.getUsername(), authConf.getPassword()); + } return storage; }
--- a/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceLauncher.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/cmd/src/main/java/com/redhat/thermostat/web/cmd/WebServiceLauncher.java Wed Nov 28 12:24:00 2012 +0100 @@ -37,18 +37,26 @@ package com.redhat.thermostat.web.cmd; +import java.io.IOException; import java.util.List; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.DefaultUserIdentity; +import org.eclipse.jetty.security.MappedLoginService; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.webapp.WebAppContext; import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.storage.MongoStorageProvider; +import com.redhat.thermostat.web.server.IpPortPair; import com.redhat.thermostat.web.server.WebStorageEndPoint; -import com.redhat.thermostat.web.server.IpPortPair; class WebServiceLauncher { @@ -76,19 +84,54 @@ connectors[i].setHost(pair.getIp()); } server.setConnectors( connectors ); - ServletHandler handler = new ServletHandler(); + + WebAppContext ctx = new WebAppContext(); + ctx.setContextPath("/"); + // This prevents useless classloading, which could fail in the face of OSGi. + ctx.setConfigurations(new org.eclipse.jetty.webapp.Configuration[0]); + ServletHolder servletHolder = new ServletHolder("rest-storage-end-point", new WebStorageEndPoint()); servletHolder.setInitParameter(WebStorageEndPoint.STORAGE_ENDPOINT, storageURL); - handler.setServlets(new ServletHolder[] { servletHolder }); - ServletMapping mapping = new ServletMapping(); - mapping.setPathSpec("/"); - mapping.setServletName("rest-storage-end-point"); - handler.setServletMappings(new ServletMapping[] { mapping }); - server.setHandler(handler); + servletHolder.setInitParameter(WebStorageEndPoint.STORAGE_CLASS, MongoStorageProvider.class.getName()); + ctx.addServlet(servletHolder, "/"); + + configureSecurity(ctx); + + server.setHandler(ctx); server.start(); server.join(); } + private void configureSecurity(WebAppContext ctx) { + ConstraintSecurityHandler secHandler = new ConstraintSecurityHandler(); + ConstraintMapping constraintMap = new ConstraintMapping(); + Constraint constraint = new Constraint(); + constraint.setAuthenticate(true); + constraint.setRoles(new String[] { "thermostat-client", "thermostat-agent" }); + constraint.setName("Entire Application"); + constraintMap.setPathSpec("/*"); + constraintMap.setConstraint(constraint); + + secHandler.setRealmName("Thermostat Realm"); + secHandler.setAuthMethod("BASIC"); + secHandler.addConstraintMapping(constraintMap); + secHandler.addRole("thermostat-agent"); + secHandler.addRole("thermostat-client"); + secHandler.setLoginService(new MappedLoginService() { + + @Override + protected void loadUsers() throws IOException { + putUser("thermostat", new Password("thermostat"), new String[] { "thermostat-agent", "thermostat-client" }); + } + + @Override + protected UserIdentity loadUser(String username) { + return new DefaultUserIdentity(null, null, new String[] { "thermostat-agent", "thermostat-client" }); + } + }); + ctx.setSecurityHandler(secHandler); + } + void stop() throws Exception { server.stop(); server.join();
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java Wed Nov 28 12:24:00 2012 +0100 @@ -37,9 +37,9 @@ package com.redhat.thermostat.web.common; +import com.redhat.thermostat.common.storage.MongoStorageProvider; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageException; import com.redhat.thermostat.storage.core.StorageProvider; public class StorageWrapper { @@ -64,7 +64,15 @@ storage.getConnection().connect(); return storage; } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new StorageException (e); + // This fallback should infact not be used. But it gives us an automatic + // Import-Package in the OSGi descriptor, which actually *prevents* this same + // exception from happening (a recursive self-defeating catch-block) :-) + System.err.println("could not instantiate provider: " + storageClass + ", falling back to MongoStorage"); + e.printStackTrace(); + StorageProvider provider = new MongoStorageProvider(); + provider.setConfig(conf); + storage = provider.createStorage(); + return storage; } } public static void setStorage(Storage storage) {
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Wed Nov 28 12:24:00 2012 +0100 @@ -82,6 +82,7 @@ @SuppressWarnings("serial") public class WebStorageEndPoint extends HttpServlet { + private static final String ROLE_THERMOSTAT_AGENT = "thermostat-agent"; private Storage storage; private Gson gson; @@ -222,6 +223,10 @@ } private void putPojo(HttpServletRequest req, HttpServletResponse resp) { + if (! req.isUserInRole(ROLE_THERMOSTAT_AGENT)) { + resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } try { String insertParam = req.getParameter("insert"); WebInsert insert = gson.fromJson(insertParam, WebInsert.class);
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Wed Nov 21 21:29:49 2012 +0100 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Wed Nov 28 12:24:00 2012 +0100 @@ -54,15 +54,16 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; -import javax.sound.midi.SysexMessage; - +import org.eclipse.jetty.security.DefaultUserIdentity; +import org.eclipse.jetty.security.MappedLoginService; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.util.security.Password; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.After; import org.junit.AfterClass; @@ -71,6 +72,8 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; +import sun.misc.BASE64Encoder; + import com.google.gson.Gson; import com.redhat.thermostat.storage.core.Categories; import com.redhat.thermostat.storage.core.Category; @@ -79,18 +82,18 @@ import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Persist; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.core.Query.SortDirection; import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; -import com.redhat.thermostat.storage.core.Query.SortDirection; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; import com.redhat.thermostat.test.MockQuery; -import com.redhat.thermostat.web.common.WebQuery; import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.WebInsert; +import com.redhat.thermostat.web.common.WebQuery; import com.redhat.thermostat.web.common.WebRemove; import com.redhat.thermostat.web.common.WebUpdate; @@ -167,7 +170,21 @@ private void startServer(int port) throws Exception { server = new Server(port); - server.setHandler(new WebAppContext("src/main/webapp", "/")); + WebAppContext ctx = new WebAppContext("src/main/webapp", "/"); + ctx.getSecurityHandler().setAuthMethod("BASIC"); + ctx.getSecurityHandler().setLoginService(new MappedLoginService() { + + @Override + protected void loadUsers() throws IOException { + putUser("testname", new Password("testpasswd"), new String[] { "thermostat-agent" }); + } + + @Override + protected UserIdentity loadUser(String username) { + return new DefaultUserIdentity(null, null, new String[] { "thermostat-agent" }); + } + }); + server.setHandler(ctx); server.start(); } @@ -271,6 +288,12 @@ URL url = new URL(endpoint + "/put-pojo"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + BASE64Encoder enc = new BASE64Encoder(); + String userpassword = "testname:testpasswd"; + String encodedAuthorization = enc.encode( userpassword.getBytes() ); + conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization); + conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); WebInsert insert = new WebInsert(categoryId, true, TestClass.class.getName()); @@ -487,6 +510,6 @@ } private String getEndpoint() { - return "http://localhost:" + port + "/storage"; + return "http://testname:testpasswd@localhost:" + port + "/storage"; } }
--- a/web/war/pom.xml Wed Nov 21 21:29:49 2012 +0100 +++ b/web/war/pom.xml Wed Nov 28 12:24:00 2012 +0100 @@ -62,6 +62,12 @@ <artifactId>thermostat-web-server</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>${javax.servlet.version}</version> + <scope>provided</scope> + </dependency> </dependencies> </project>
--- a/web/war/src/main/webapp/WEB-INF/web.xml Wed Nov 21 21:29:49 2012 +0100 +++ b/web/war/src/main/webapp/WEB-INF/web.xml Wed Nov 28 12:24:00 2012 +0100 @@ -23,4 +23,28 @@ <servlet-name>reststorage-servlet</servlet-name> <url-pattern>/storage/*</url-pattern> </servlet-mapping> + + <security-constraint> + <web-resource-collection> + <web-resource-name>Entire Application</web-resource-name> + <url-pattern>/*</url-pattern> + </web-resource-collection> + <auth-constraint> + <role-name>thermostat-agent</role-name> + <role-name>thermostat-client</role-name> + </auth-constraint> + </security-constraint> + + <login-config> + <auth-method>BASIC</auth-method> + <realm-name>Thermostat Realm</realm-name> + </login-config> + + <security-role> + <role-name>thermostat-agent</role-name> + </security-role> + <security-role> + <role-name>thermostat-client</role-name> + </security-role> + </web-app>