/* * Copyright (c) 2015 Shervin Asgari * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package no.asgari.civilization.server.resource; import com.codahale.metrics.annotation.Timed; import com.google.common.base.CharMatcher; import com.google.common.base.Preconditions; import com.google.common.html.HtmlEscapers; import com.mongodb.BasicDBObject; import com.mongodb.DB; import io.dropwizard.auth.basic.BasicCredentials; import lombok.Cleanup; import lombok.extern.log4j.Log4j; import no.asgari.civilization.server.action.PlayerAction; import no.asgari.civilization.server.application.CivAuthenticator; import no.asgari.civilization.server.dto.CheckNameDTO; import no.asgari.civilization.server.dto.ForgotpassDTO; import no.asgari.civilization.server.model.Player; import org.mongojack.DBCursor; import org.mongojack.DBQuery; import org.mongojack.JacksonDBCollection; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; import java.util.Optional; @Path("auth") @Log4j @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class AuthResource { private final DB db; private final JacksonDBCollection<Player, String> playerCollection; @Context private UriInfo uriInfo; public AuthResource(DB db) { this.db = db; this.playerCollection = JacksonDBCollection.wrap(db.getCollection(Player.COL_NAME), Player.class, String.class); } @POST @Consumes(value = MediaType.APPLICATION_FORM_URLENCODED) @Produces(value = MediaType.APPLICATION_JSON) @Path("/login") public Response login(@FormParam("username") @NotNull String username, @FormParam("password") @NotNull String password) { Preconditions.checkNotNull(username); Preconditions.checkNotNull(password); CivAuthenticator auth = new CivAuthenticator(db); Optional<Player> playerOptional = auth.authenticate(new BasicCredentials(username, password)); if (playerOptional.isPresent()) { Player player = playerOptional.get(); URI games = uriInfo.getBaseUriBuilder() .path("/player/") .path(player.getId()) .path("/games") .build(); player.setPassword(""); return Response.ok() .entity(player) .location(games) .build(); } return Response.status(Response.Status.FORBIDDEN).build(); } @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Path("/register") public Response register(@FormParam("username") @NotNull String username, @FormParam("password") @NotNull String password, @FormParam("email") @NotNull String email) { Preconditions.checkNotNull(username); Preconditions.checkNotNull(password); Preconditions.checkNotNull(email); PlayerAction playerAction = new PlayerAction(db); try { String playerId = playerAction.createPlayer(username, password, email); return Response.status(Response.Status.CREATED) .location(uriInfo.getAbsolutePathBuilder().path(playerId).build()) .entity("{\"id\": \"" + playerId + "\"}") .build(); } catch (WebApplicationException ex) { return ex.getResponse(); } catch (Exception ex) { log.error("Unknown error when registering user: " + ex.getMessage(), ex); return Response.status(Response.Status.BAD_REQUEST).build(); } } @POST @Path("/register/check/username") public Response checkUsername(CheckNameDTO nameDTO) { Preconditions.checkNotNull(nameDTO); if(CharMatcher.WHITESPACE.matchesAnyOf(nameDTO.getName())) { return Response.status(Response.Status.FORBIDDEN).entity("{\"space\":\"true\"}").build(); } //If these doesn't match, then the username is unsafe if (!nameDTO.getName().equals(HtmlEscapers.htmlEscaper().escape(nameDTO.getName()))) { log.warn("Unsafe username " + nameDTO.getName()); return Response.status(Response.Status.FORBIDDEN).entity("{\"invalidChars\":\"true\"}").build(); } @Cleanup DBCursor<Player> dbPlayer = playerCollection.find( DBQuery.is("username", nameDTO.getName().trim()), new BasicDBObject()); if (dbPlayer.hasNext()) { return Response.status(Response.Status.FORBIDDEN).entity("{\"isTaken\":\"true\"}").build(); } return Response.ok().build(); } @PUT @Path("/newpassword") @Timed public Response newPassword(ForgotpassDTO forgotpassDTO) { PlayerAction playerAction = new PlayerAction(db); boolean yes = playerAction.newPassword(forgotpassDTO); if (yes) { return Response.ok().build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } } @Path("/verify/{playerId}") @GET @Produces(MediaType.TEXT_HTML) public Response verifyPassword(@PathParam("playerId") String playerId) { PlayerAction playerAction = new PlayerAction(db); boolean yes = playerAction.verifyPassword(playerId); if (yes) { return Response.ok().entity("<html>Your password was correctly changed. <a href=\"http://playciv.com\">Try to login again </a></html>").build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } } }