# HG changeset patch # User Jaroslav Tulach # Date 1252853334 -7200 # Node ID 9ac7acee7d9f34dc1b6cc7b36bb4197ae3042c15 # Parent 1174c9dcab41143560c9904b1230e3cf100cdaf2 Providing REST like authentication diff -r 1174c9dcab41 -r 9ac7acee7d9f freemarkerdor/pom.xml --- a/freemarkerdor/pom.xml Sat Sep 12 10:02:07 2009 +0200 +++ b/freemarkerdor/pom.xml Sun Sep 13 16:48:54 2009 +0200 @@ -15,7 +15,7 @@ ${project.groupId} webidor - 1.0 + 1.1 org.netbeans.modules @@ -100,7 +100,7 @@ - 1.4 + 1.5 diff -r 1174c9dcab41 -r 9ac7acee7d9f freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Sat Sep 12 10:02:07 2009 +0200 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Sun Sep 13 16:48:54 2009 +0200 @@ -35,14 +35,11 @@ import com.sun.jersey.api.view.Viewable; import com.sun.net.httpserver.HttpServer; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; -import java.util.Properties; import java.util.ResourceBundle; import java.util.concurrent.Callable; import javax.ws.rs.DefaultValue; @@ -71,13 +68,16 @@ @Context private HttpHeaders headers; private String user; + private String uuid; public UI() { } private Viewable checkLogin() { if (headers.getCookies().containsKey("login")) { - user = headers.getCookies().get("login").getValue(); + uuid = headers.getCookies().get("login").getValue(); + user = base.path("login").queryParam("id", uuid). + accept(MediaType.TEXT_PLAIN).get(String.class); return null; } return viewable("login.fmt", null); @@ -89,16 +89,11 @@ public Response login( @FormParam("name") String name, @FormParam("password") String password ) throws Exception { - File f = new File(new File(System.getProperty("quoridor.dir")), "passwd"); - Properties p = new Properties(); - try { - p.load(new FileInputStream(f)); - } catch (IOException ex) { - ex.printStackTrace(); - } - if (name != null && password.equals(p.getProperty(name))) { + uuid = base.path("login").queryParam("name", name).queryParam("password", password). + accept(MediaType.TEXT_PLAIN).put(String.class); + if (uuid != null) { user = name; - return Response.ok().cookie(new NewCookie("login", name)).entity(viewable("login.fmt", null)).build(); + return Response.ok().cookie(new NewCookie("login", uuid)).entity(viewable("login.fmt", null)).build(); } else { Viewable v = viewable("login.fmt", null, "message", "Invalid name or password: " + name); return Response.status(1).entity(v).build(); @@ -145,7 +140,9 @@ if (v != null) { return v; } - WebResource wr = base.path("games").path(id).queryParam("player", user); + WebResource wr = base.path("games").path(id). + queryParam("loginID", uuid). + queryParam("player", user); try { if (type.equals("resign")) { wr.queryParam("move", "RESIGN").put(); @@ -179,7 +176,9 @@ if (user.equals(white) || user.equals(black)) { Object obj = - base.path("games").queryParam("white", white). + base.path("games"). + queryParam("loginID", uuid). + queryParam("white", white). queryParam("black", black).accept(MediaType.TEXT_XML).post(Document.class); return Response.ok(welcomeImpl()).build(); } else { diff -r 1174c9dcab41 -r 9ac7acee7d9f freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java --- a/freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java Sat Sep 12 10:02:07 2009 +0200 +++ b/freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java Sun Sep 13 16:48:54 2009 +0200 @@ -38,6 +38,7 @@ import java.util.Locale; import java.util.concurrent.Callable; import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import org.junit.AfterClass; import org.junit.Before; @@ -68,7 +69,7 @@ File passwd = new File(dir, "passwd"); FileOutputStream os = new FileOutputStream(passwd); - os.write("test=pes\n".getBytes("UTF-8")); + os.write("test=pes\nJarda=darda\n".getBytes("UTF-8")); os.close(); } @@ -111,6 +112,13 @@ } @Test public void testGetIndexPage() throws Exception { + String logJarda = webResource.path("api/login"). + queryParam("name", "Jarda"). + queryParam("password", "darda"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + assertNotNull("Logged in OK", logJarda); + String res = webResource.accept("text/html").get(String.class); if (res.indexOf("Quoridor") == -1) { fail("Wrong index.html:\n" + res); @@ -124,7 +132,7 @@ if (res.toLowerCase().indexOf("error") != -1) { fail("There was an error:\n" + res); } - res = webResource.cookie(Cookie.valueOf("login=jarda")).accept("text/html").get(String.class); + res = webResource.cookie(Cookie.valueOf("login=" + logJarda)).accept("text/html").get(String.class); if (res.indexOf("action=\"/games/create\"") == -1) { fail(res); } @@ -146,10 +154,15 @@ @Test public void testCreateGameWrongUsers() throws Exception { + String logTest = webResource.path("api/login"). + queryParam("name", "test"). + queryParam("password", "pes"). + accept(MediaType.TEXT_PLAIN). + put(String.class); ClientResponse res = webResource.path("games/create"). queryParam("white", "unknown1"). queryParam("black", "unknown2"). - cookie(Cookie.valueOf("login=test")). + cookie(Cookie.valueOf("login=" + logTest)). accept("text/html"). get(ClientResponse.class); final String txt = res.getEntity(String.class); @@ -160,10 +173,15 @@ } @Test public void testCreateGameOK() throws Exception { + String logTest = webResource.path("api/login"). + queryParam("name", "test"). + queryParam("password", "pes"). + accept(MediaType.TEXT_PLAIN). + put(String.class); ClientResponse res = webResource.path("games/create"). queryParam("white", "unknown1"). queryParam("black", "test"). - cookie(Cookie.valueOf("login=test")). + cookie(Cookie.valueOf("login=" + logTest)). accept("text/html"). get(ClientResponse.class); diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/pom.xml --- a/webidor/pom.xml Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/pom.xml Sun Sep 13 16:48:54 2009 +0200 @@ -9,7 +9,7 @@ org.apidesign webidor jar - 1.0 + 1.1 webidor server http://maven.apache.org diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java Sun Sep 13 16:48:54 2009 +0200 @@ -48,19 +48,23 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; /** * * @author Jaroslav Tulach */ public final class Games { + private final Quoridor quoridor; private final List games = new ArrayList(); private final File dir; private static final Logger LOG = Logger.getLogger(Games.class.getName()); - public Games(File dir) { + public Games(File dir, Quoridor quoridor) { this.dir = dir; + this.quoridor = quoridor; File[] arr = dir.listFiles(); if (arr != null) { for (File f : arr) { @@ -77,15 +81,24 @@ @POST @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) public GameId createGame( + @QueryParam("loginID") String id, @QueryParam("white") String white, @QueryParam("black") String black ) throws IOException { + String logUser = quoridor.isLoggedIn(id); + if (logUser == null) { + throw new WebApplicationException(Status.UNAUTHORIZED); + } if (white == null) { - throw new IllegalArgumentException("Must specify white"); + throw new WebApplicationException(Status.PRECONDITION_FAILED); } if (black == null) { - throw new IllegalArgumentException("Must specify black"); + throw new WebApplicationException(Status.PRECONDITION_FAILED); } + if (!logUser.equals(white) && !logUser.equals(black)) { + throw new WebApplicationException(Status.PRECONDITION_FAILED); + } + Game g = new Game(white, black); storeGame(g); games.add(g); @@ -118,10 +131,19 @@ @Path("{id}") @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) public GameId applyMove( + @QueryParam("loginID") String loginId, @PathParam("id") String id, @QueryParam("player") String player, @QueryParam("move") String move ) throws IllegalPositionException { + String logUser = quoridor.isLoggedIn(loginId); + if (logUser == null) { + throw new WebApplicationException(Status.UNAUTHORIZED); + } + if (!logUser.equals(player)) { + throw new WebApplicationException(Status.UNAUTHORIZED); + } + Game g = findGame(id); if (g == null) { throw new IllegalArgumentException("Unknown game " + id); diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java Sun Sep 13 16:48:54 2009 +0200 @@ -32,9 +32,19 @@ import com.sun.jersey.spi.resource.Singleton; import com.sun.net.httpserver.HttpServer; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.net.ServerSocket; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; /** * @@ -45,6 +55,7 @@ public final class Quoridor { private final File path; private Games games; + private final Map loggedIn; public Quoridor() { final String prop = System.getProperty("quoridor.dir"); // NOI18N @@ -53,16 +64,50 @@ } path = new File(prop); path.mkdirs(); + loggedIn = new HashMap(); } @Path("games") public Games getGames() { if (games == null) { - games = new Games(new File(path, "games")); + games = new Games(new File(path, "games"), this); // NOI18N } return games; } + @Path("login") + @PUT + @Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public String login( + @QueryParam("name") String name, + @QueryParam("password") String password + ) { + File f = new File(path, "passwd"); // NOI18Nt + Properties p = new Properties(); + try { + p.load(new FileInputStream(f)); + } catch (IOException ex) { + ex.printStackTrace(); + } + if (name != null && password.equals(p.getProperty(name))) { + UUID uuid = UUID.randomUUID(); + loggedIn.put(uuid, name); + return uuid.toString(); + } else { + return null; + } + + } + + @Path("login") + @GET + @Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public String isLoggedIn( + @QueryParam("id") String id + ) { + return id == null ? null : loggedIn.get(UUID.fromString(id)); + } + // // start the server // diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java Sun Sep 13 16:48:54 2009 +0200 @@ -28,6 +28,7 @@ import com.sun.jersey.test.framework.JerseyTest; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import javax.ws.rs.core.MediaType; import org.junit.Test; @@ -49,6 +50,11 @@ dir = File.createTempFile("quoridor", ".dir"); dir.delete(); System.setProperty("quoridor.dir", dir.getPath()); + dir.mkdirs(); + File passwd = new File(dir, "passwd"); + FileOutputStream os = new FileOutputStream(passwd); + os.write("Jarda=heslo\nJirka=pesko\n".getBytes("UTF-8")); + os.close(); super.setUp(); } @@ -73,20 +79,44 @@ @Test public void testCreateAGame() throws Exception { webResource = webResource.path("api"); + String logJarda = webResource.path("login"). + queryParam("name", "Jarda"). + queryParam("password", "heslo"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + String logJirka = webResource.path("login"). + queryParam("name", "Jirka"). + queryParam("password", "pesko"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + assertNotNull("Logged in ok", logJarda); GameId s = webResource.path("games").queryParam("white", "Jarda") + .queryParam("loginID", logJarda) .queryParam("black", "Jirka").post(GameId.class); for (int i = 0; i < 3; i++) { - webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); - webResource.path("games/" + s.getId()).queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJarda) + .queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJirka) + .queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); } - webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); - webResource.path("games/" + s.getId()).queryParam("player", "Jirka").queryParam("move", "SS").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJarda) + .queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJirka) + .queryParam("player", "Jirka").queryParam("move", "SS").put(GameId.class); for (int i = 0; i < 3; i++) { - webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); - webResource.path("games/" + s.getId()).queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJarda) + .queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); + webResource.path("games/" + s.getId()) + .queryParam("loginID", logJirka) + .queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); } Game end = webResource.path("games/" + s.getId()).accept(MediaType.TEXT_XML).get(Game.class); @@ -95,10 +125,19 @@ @Test public void testResignAGame() throws Exception { webResource = webResource.path("api"); + String logJarda = webResource.path("login"). + queryParam("name", "Jarda"). + queryParam("password", "heslo"). + accept(MediaType.TEXT_PLAIN). + put(String.class); GameId s = webResource.path("games").queryParam("white", "Jarda") + .queryParam("loginID", logJarda) .queryParam("black", "Jirka").post(GameId.class); - webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "RESIGN").put(GameId.class); + webResource.path("games/" + s.getId()). + queryParam("loginID", logJarda). + queryParam("player", "Jarda"). + queryParam("move", "RESIGN").put(GameId.class); Game end = webResource.path("games/" + s.getId()).accept(MediaType.TEXT_XML).get(Game.class); assertEquals("BlackWins", GameStatus.blackWon, end.getId().getStatus()); } diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/src/test/java/cz/xelfi/quoridor/webidor/GamesTest.java --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/GamesTest.java Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/GamesTest.java Sun Sep 13 16:48:54 2009 +0200 @@ -27,6 +27,7 @@ package cz.xelfi.quoridor.webidor; import cz.xelfi.quoridor.webidor.resources.Games; +import cz.xelfi.quoridor.webidor.resources.Quoridor; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -80,7 +81,7 @@ Thread.sleep(1000); - Games games = new Games(dir); + Games games = new Games(dir, new Quoridor()); Game g = games.getBoardInfo("x"); assertNotNull("Game found", g); assertNotNull("Board found", g.getBoard()); diff -r 1174c9dcab41 -r 9ac7acee7d9f webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Sat Sep 12 10:02:07 2009 +0200 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Sun Sep 13 16:48:54 2009 +0200 @@ -33,7 +33,9 @@ import cz.xelfi.quoridor.Board; import cz.xelfi.quoridor.Move; import cz.xelfi.quoridor.webidor.resources.Games; +import cz.xelfi.quoridor.webidor.resources.Quoridor; import java.io.File; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.List; @@ -59,6 +61,11 @@ dir = File.createTempFile("quoridor", ".dir"); dir.delete(); System.setProperty("quoridor.dir", dir.getPath()); + dir.mkdirs(); + File passwd = new File(dir, "passwd"); + FileOutputStream os = new FileOutputStream(passwd); + os.write("Jarda=heslo\nJirka=pesko\n".getBytes("UTF-8")); + os.close(); super.setUp(); } @@ -93,7 +100,18 @@ @Test public void testCreateAGame() throws Exception { webResource = webResource.path("api"); - GameId s = webResource.path("games").queryParam("white", "Jarda") + String logJarda = webResource.path("login"). + queryParam("name", "Jarda"). + queryParam("password", "heslo"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + String logJirka = webResource.path("login"). + queryParam("name", "Jirka"). + queryParam("password", "pesko"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + GameId s = webResource.path("games").queryParam("loginID", logJarda). + queryParam("white", "Jarda") .queryParam("black", "Jirka").post(GameId.class); Thread.sleep(100); @@ -117,20 +135,28 @@ assertEquals("Same white", "Jarda", games.get(0).getWhite()); assertEquals("Same black", "Jirka", games.get(0).getBlack()); - GameId s1 = webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); + GameId s1 = webResource.path("games/" + s.getId()). + queryParam("loginID", logJarda). + queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); try { - GameId s2 = webResource.path("games/" + s.getId()).queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); + GameId s2 = webResource.path("games/" + s.getId()). + queryParam("loginID", logJarda). + queryParam("player", "Jarda").queryParam("move", "N").put(GameId.class); fail("Not Jarda's turn, previous call shall fail"); } catch (UniformInterfaceException ex) { // OK } try { - GameId s2 = webResource.path("games/" + s.getId()).queryParam("player", "Jirka").queryParam("move", "NONSENCE").put(GameId.class); + GameId s2 = webResource.path("games/" + s.getId()). + queryParam("loginID", logJirka). + queryParam("player", "Jirka").queryParam("move", "NONSENCE").put(GameId.class); fail("Invalid move"); } catch (UniformInterfaceException ex) { // OK } - GameId s2 = webResource.path("games/" + s.getId()).queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); + GameId s2 = webResource.path("games/" + s.getId()). + queryParam("loginID", logJirka). + queryParam("player", "Jirka").queryParam("move", "S").put(GameId.class); assertNotNull("Successful move", s2); if (s2.getModified() <= now) { fail("The game is newly modified"); @@ -154,7 +180,7 @@ fail(content); } - Games read = new Games(new File(dir, "games")); + Games read = new Games(new File(dir, "games"), new Quoridor()); List readGames = read.getGames(); assertEquals("One game read", 1, readGames.size()); Board board = readGames.get(0).getBoard();