Skip to content

Commit

Permalink
- make access tokens usable (for a test: getting the current user
Browse files Browse the repository at this point in the history
requires a token)
- move stuff around
  • Loading branch information
Shujito committed May 21, 2015
1 parent d763fd2 commit bcc99a7
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 66 deletions.
3 changes: 2 additions & 1 deletion src/org/shujito/ucs/GsonWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ private GsonWrapper()
throw new RuntimeException();
ExcludeFieldsWithoutSerializedName efwosn = new ExcludeFieldsWithoutSerializedName();
this.mGson = new GsonBuilder()
//.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX")
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX")
//.disableHtmlEscaping()
.addDeserializationExclusionStrategy(efwosn)
.addSerializationExclusionStrategy(efwosn)
.registerTypeHierarchyAdapter(byte[].class, new ByteArrayToBase64Serializer())
Expand Down
75 changes: 18 additions & 57 deletions src/org/shujito/ucs/controllers/Users.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package org.shujito.ucs.controllers;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Singleton;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
Expand All @@ -20,7 +15,6 @@

import org.shujito.ucs.ApiException;
import org.shujito.ucs.Constants;
import org.shujito.ucs.db.Database;
import org.shujito.ucs.models.Session;
import org.shujito.ucs.models.User;
import org.shujito.ucs.models.User.Validation;
Expand All @@ -37,38 +31,22 @@ public class Users
@GET
public synchronized Response index() throws Exception
{
try (Statement smt = Database.createStatement())
{
try (ResultSet rs = smt.executeQuery("select uuid,created_at,display_name as username from users where deleted_at is null order by username asc"))
{
List<User> users = new ArrayList<>();
while (rs.next())
{
User user = User.fromResultSet(rs);
users.add(user);
}
return Response.ok(users).build();
}
}
return Response.ok(User.getAll()).build();
}

@GET
@Path("{uuid}")
public synchronized Response index(@PathParam("uuid") String uuid) throws Exception
{
try (PreparedStatement smt = Database.prepareStatement("select created_at,display_name as username from users where uuid = ? and deleted_at is null"))
{
smt.setString(1, uuid);
try (ResultSet rs = smt.executeQuery())
{
if (rs.next())
{
User user = User.fromResultSet(rs);
return Response.ok(user).build();
}
}
}
throw new ApiException(Constants.Strings.USER_DOES_NOT_EXIST, Status.NOT_FOUND.getStatusCode());
return Response.ok(User.fromUuid(uuid)).build();
}

@GET
@Path("/me")
public synchronized Response me(@BeanParam User user) throws Exception
{
user.continueOrThrow();
return Response.ok(user).build();
}

@POST
Expand Down Expand Up @@ -96,29 +74,12 @@ public synchronized Response login(User user, @HeaderParam("user-agent") String
if (user == null)
throw new ApiException(Constants.Strings.MISSING_CONTENT_BODY, Status.NOT_ACCEPTABLE.getStatusCode());
user.validate(new Validation(true, true, false));
try (PreparedStatement psm = Database.prepareStatement("select "
+ "users.uuid as user_uuid,"
+ "user_passwords.password as password,"
+ "user_passwords.salt as salt"
+ " from users"
+ " inner join user_passwords"
+ " on users.uuid=user_passwords.user_uuid"
+ " where users.username=lower(?)"))
{
psm.setString(1, user.username);
try (ResultSet rs = psm.executeQuery())
{
if (!rs.next())
throw new ApiException(Constants.Strings.USER_DOES_NOT_EXIST, Status.NOT_FOUND.getStatusCode());
UserPassword sup = UserPassword.fromResultSet(rs);
UserPassword oup = new UserPassword(user.password.getBytes(), sup.salt);
//oup.hashPassword();
if (!sup.equals(oup))
throw new ApiException(Constants.Strings.INVALID_CREDENTIALS, Status.FORBIDDEN.getStatusCode());
Session session = new Session(sup.userUuid, userAgent);
session.save();
return Response.ok(session).build();
}
}
UserPassword sup = UserPassword.fromUsername(user.username);
UserPassword oup = new UserPassword(user.password.getBytes(), sup.salt);
if (!sup.equals(oup))
throw new ApiException(Constants.Strings.INVALID_CREDENTIALS, Status.FORBIDDEN.getStatusCode());
Session session = new Session(sup.userUuid, userAgent);
session.save();
return Response.ok(session).build();
}
}
122 changes: 114 additions & 8 deletions src/org/shujito/ucs/models/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.ws.rs.HeaderParam;
import javax.ws.rs.core.Response.Status;

import org.apache.commons.validator.routines.EmailValidator;
import org.shujito.ucs.ApiException;
import org.shujito.ucs.Constants;
import org.shujito.ucs.Crypto;
import org.shujito.ucs.db.Database;

import com.google.gson.annotations.SerializedName;
Expand Down Expand Up @@ -50,6 +55,42 @@ public Validation(boolean username, boolean password, boolean email)
public static final String PASSWORD_SALT = "password_salt";
public static final String EMAIL = "email";

public static List<User> getAll() throws Exception
{
try (Statement smt = Database.createStatement())
{
try (ResultSet rs = smt
.executeQuery("select uuid,created_at,display_name as username from users where deleted_at is null order by username asc"))
{
List<User> users = new ArrayList<>();
while (rs.next())
{
User user = User.fromResultSet(rs);
users.add(user);
}
return users;
}
}
}

public static User fromUuid(String uuid) throws Exception
{
try (PreparedStatement smt = Database
.prepareStatement("select created_at,display_name as username from users where uuid = ? and deleted_at is null"))
{
smt.setString(1, uuid);
try (ResultSet rs = smt.executeQuery())
{
if (rs.next())
{
User user = User.fromResultSet(rs);
return user;
}
}
throw new ApiException(Constants.Strings.USER_DOES_NOT_EXIST, Status.NOT_FOUND.getStatusCode());
}
}

public static User fromResultSet(ResultSet rs) throws Exception
{
ResultSetMetaData rsmd = rs.getMetaData();
Expand Down Expand Up @@ -104,6 +145,64 @@ public static User fromResultSet(ResultSet rs) throws Exception
public String email;
@SerializedName(PASSWORD)
public String password;
private Exception exception;

public User()
{
}

public User(@HeaderParam("access-token") String accessToken, @HeaderParam("user-agent") String userAgent) throws Exception
{
if (accessToken == null)
{
this.exception = new ApiException(Constants.Strings.ACCESS_DENIED, Status.FORBIDDEN.getStatusCode());
return;
}
if (accessToken.length() != 44)
{
this.exception = new ApiException(Constants.Strings.MALFORMED_ACCESS_TOKEN, Status.FORBIDDEN.getStatusCode());
return;
}
byte[] tokenBytes = Crypto.base64decode(accessToken);
try (PreparedStatement psm = Database
.prepareStatement("select "
+ "users.uuid,"
+ "users.created_at,"
+ "users.updated_at,"
+ "users.username,"
+ "users.display_name,"
+ "users.email"
+ " from users"
+ " inner join sessions"
+ " on users.uuid=sessions.user_uuid"
+ " where users.deleted_at is null"
+ " and datetime(sessions.expires_at/1000,'unixepoch','localtime') > datetime('now','localtime')"
+ " and sessions.access_token=?"))
{
psm.setBytes(1, tokenBytes);
try (ResultSet rs = psm.executeQuery())
{
if (!rs.next())
throw new ApiException(Constants.Strings.ACCESS_DENIED, Status.FORBIDDEN.getStatusCode());
this.loadResultSet(rs);
}
}
catch (Exception ex)
{
this.exception = ex;
}
}

private void loadResultSet(ResultSet rs) throws Exception
{
User user = User.fromResultSet(rs);
this.uuid = user.uuid;
this.createdAt = user.createdAt;
this.updatedAt = user.updatedAt;
this.deletedAt = user.deletedAt;
this.username = user.username;
this.displayName = user.displayName;
}

public void validate(Validation validate)
{
Expand All @@ -123,22 +222,29 @@ public void validate(Validation validate)
throw new ApiException(Constants.Strings.INVALID_EMAIL_ADDRESS, Status.NOT_ACCEPTABLE.getStatusCode());
}

public void continueOrThrow() throws Exception
{
if (this.exception != null)
throw this.exception;
}

public void load() throws Exception
{
try (PreparedStatement psm = Database.prepareStatement("select uuid,created_at,updated_at,deleted_at,username,display_name from users where username = lower(?) and deleted_at is null"))
try (PreparedStatement psm = Database.prepareStatement("select "
+ "uuid,"
+ "created_at,"
+ "updated_at,"
+ "deleted_at,"
+ "username,"
+ "display_name"
+ " from users where username = lower(?) and deleted_at is null"))
{
psm.setString(1, this.username);
try (ResultSet rs = psm.executeQuery())
{
if (!rs.next())
throw new ApiException(Constants.Strings.USER_DOES_NOT_EXIST, Status.NOT_FOUND.getStatusCode());
User user = User.fromResultSet(rs);
this.uuid = user.uuid;
this.createdAt = user.createdAt;
this.updatedAt = user.updatedAt;
this.deletedAt = user.deletedAt;
this.username = user.username;
this.displayName = user.displayName;
this.loadResultSet(rs);
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions src/org/shujito/ucs/models/UserPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

import javax.ws.rs.core.Response.Status;

import org.shujito.ucs.ApiException;
import org.shujito.ucs.Constants;
import org.shujito.ucs.Crypto;
import org.shujito.ucs.db.Database;

Expand Down Expand Up @@ -38,6 +42,27 @@ public static UserPassword fromResultSet(ResultSet rs) throws Exception
return up;
}

public static UserPassword fromUsername(String username) throws Exception
{
try (PreparedStatement psm = Database.prepareStatement("select "
+ "users.uuid as user_uuid,"
+ "user_passwords.password as password,"
+ "user_passwords.salt as salt"
+ " from users"
+ " inner join user_passwords"
+ " on users.uuid=user_passwords.user_uuid"
+ " where users.username=lower(?)"))
{
psm.setString(1, username);
try (ResultSet rs = psm.executeQuery())
{
if (!rs.next())
throw new ApiException(Constants.Strings.USER_DOES_NOT_EXIST, Status.NOT_FOUND.getStatusCode());
return UserPassword.fromResultSet(rs);
}
}
}

public String userUuid;
public byte[] password;
public byte[] salt;
Expand Down

0 comments on commit bcc99a7

Please sign in to comment.