Skip to content

Commit

Permalink
interfaces and entities for security component, integration of securi…
Browse files Browse the repository at this point in the history
…ty component with dropwizard, initial implementation of an albums resource (not finished), added user management component (query interface only)
  • Loading branch information
mguenther committed Oct 9, 2015
1 parent 4667257 commit 4ed2de0
Show file tree
Hide file tree
Showing 23 changed files with 618 additions and 4 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ photoalbum.iml
photoalbum-couchdb-adapter/photoalbum-couchdb-adapter.iml
photoalbum-management/photoalbum-management.iml
photoalbum-common/photoalbum-common.iml
photoalbum-fileio-adapter/photoalbum-fileio-adapter.iml
photoalbum-fileio-adapter/photoalbum-fileio-adapter.iml
photoalbum-security/photoalbum-security.iml
photoalbum-user-management/photoalbum-user-management.iml
43 changes: 43 additions & 0 deletions photoalbum-security/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>photoalbum</artifactId>
<groupId>com.mgu.photoalbum</groupId>
<version>0.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>photoalbum-security</artifactId>
<packaging>jar</packaging>

<name>photoalbum-security</name>
<url>https://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<!-- Intra-project dependencies -->
<dependency>
<groupId>com.mgu.photoalbum</groupId>
<artifactId>photoalbum-user-management</artifactId>
<version>${photoalbum.version}</version>
</dependency>
<!-- Utilities -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.mgu.photoalbum.security;

import com.google.common.base.Optional;

/**
* Provides the means to authenticate a user based on given credentials.
*
* @author Markus Günther ([email protected])
*/
public interface Authentication {

/**
* Uses the given {@link Credentials} to authenticate the user within the
* photoalbum service. If the authentication fails, the resulting {@link Optional}
* will carry no value. If it succeeds, the {@link Optional} will wrap an
* instance of {@link Principal}, which is an injectable POJO that can be
* used in resource method signatures (cf. <code>Auth</code> annotation).
*
* @param credentials
* contains user-supplied credentials which are used to authenticate
* the user
* @return
* {@link Optional} containing an instance of {@link Principal}
*/
Optional<Principal> authenticate(Credentials credentials);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.mgu.photoalbum.security;

/**
* Provides the means to authorize an already authenticated user (cf. {@link Principal})
* for accessing managed content within the photoalbum service.
*
* @author Markus Günther ([email protected])
*/
public interface Authorization {

/**
* Determines whether the given {@link Principal} is allowed to access content that is
* associated with the owner ID given by <code>ownerId</code>.
*
* Content like albums and photos is always associated with an owner, where an owner is a
* regular user within the system. The authenticated user (cf. {@link Principal}) is allowed to
* access this content if one of the following conditions evaluates to true (please bear
* in mind that this component has no notion of what content is addressed; access rules are
* solely based on matching user IDs (for an authenticated user) to owner IDs):
*
* <ul>
* <li>The ID of the authenticated user is the same as the owner ID associated with
* the requested content</li>
* </ul>
*
* Every other case *must* evaluate to false.
*
* @param principal
* represents an authenticated user within the photoalbum service
* @param ownerId
* represents the owner ID for which the client needs to determine whether the
* authenticated user is allowed to access content that is associated with that owner ID
* @return
* <code>true</code> if the authenticated user is authorized, <code>false</code> otherwise
*/
boolean isAuthorized(Principal principal, String ownerId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.mgu.photoalbum.security;

import org.apache.commons.codec.digest.DigestUtils;

/**
* This POJO represents simple HTTP Basic Auth credentials. Passwords in HTTP
* Basic Auth cross our system boundary unhashed, so we hash them (cf.
* {@link Credentials#create(String, String)}) using a SHA-1 digest before
* we process authentication requests any further. Passwords stored within an
* instance of <code>Credentials</code> are always encrypted.
*
* @author Markus Günther ([email protected])
*/
public class Credentials {

private final String userId;

private final String hashedPassword;

private Credentials(final String userId, final String hashedPassword) {
this.userId = userId;
this.hashedPassword = hashedPassword;
}

public String getUserId() {
return userId;
}

public String getHashedPassword() {
return hashedPassword;
}

/**
* Determines whether the given <code>otherHashedPassword</code> is
* identical to <code>Credentials.hashedPassword</code>.
*
* @param otherHashedPassword
* hashed password that ought to be compared to the stored
* hashed password within an instance of this class
* @return
* <code>true</code> if both passwords match, <code>false</code>
* otherwise
*/
public boolean matches(final String otherHashedPassword) {
return this.hashedPassword.equals(otherHashedPassword);
}

/**
* Constructs an instance of {@link Credentials} based on the given parameters.
* Passwords are not hashed when they hit the system, so we hash them using a
* SHA-1 digest on the server-side before going any further.
*
* @param userId
* identifies a user within the CREAM system
* @param cleartextPassword
* associated password in cleartext; will be hashed using SHA-1
* @return
* instance of {@link Credentials} containing the user ID along with
* the hashed password
*/
public static Credentials create(final String userId, final String cleartextPassword) {
final String hashedPassword = DigestUtils.sha1Hex(cleartextPassword);
return new Credentials(userId, hashedPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.mgu.photoalbum.security;

import com.mgu.photoalbum.user.User;

/**
* This POJO represents an authenticated user within the photoalbum service. It is barely more
* than a simple data holder for a user ID.
*
* @author Markus Günther ([email protected])
*/
public class Principal {

private final String userId;

private final String displayName;

public Principal(final String userId, final String displayName) {
this.userId = userId;
this.displayName = displayName;
}

public String getUserId() {
return userId;
}

public String getDisplayName() {
return displayName;
}

public static Principal from(final User user) {
final String displayName = user.getFirstName() + " " + user.getLastName();
return new Principal(user.getId(), displayName);
}
}
46 changes: 46 additions & 0 deletions photoalbum-user-management/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>photoalbum</artifactId>
<groupId>com.mgu.photoalbum</groupId>
<version>0.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>photoalbum-user-management</artifactId>
<packaging>jar</packaging>

<name>[photoalbum] User Management</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<!-- Intra-project dependencies -->
<dependency>
<groupId>com.mgu.photoalbum</groupId>
<artifactId>photoalbum-couchdb-adapter</artifactId>
<version>${photoalbum.version}</version>
</dependency>
<!-- Utilities -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mgu.photoalbum.user;

public enum Status {

PENDING, ACTIVE, SUSPENDED;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.mgu.photoalbum.user;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mgu.photoalbum.adapter.couchdb.Document;

public class User extends Document {

public static final String DOCUMENT_TYPE = "user";

private static final long serialVersionUID = -54352348232L;

private String firstName;

private String lastName;

private String email;

private String hashedPassword;

private Status status;

public User() {
super(DOCUMENT_TYPE);
}

public String getFirstName() {
return firstName;
}

public void setFirstName(final String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(final String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(final String email) {
this.email = email;
}

public String getHashedPassword() {
return hashedPassword;
}

public void setHashedPassword(final String hashedPassword) {
this.hashedPassword = hashedPassword;
}

public Status getStatus() {
return status;
}

public void setStatus(final Status status) {
this.status = status;
}

@JsonIgnore
public boolean isSuspended() {
return this.status == Status.SUSPENDED;
}

@JsonIgnore
public boolean isActive() {
return this.status == Status.ACTIVE;
}

@JsonIgnore
public boolean isPending() {
return this.status == Status.PENDING;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.mgu.photoalbum.user;

import com.google.common.base.Optional;

/**
* Query interface for all things related to {@link User} documents.
*
* @author Markus Günther ([email protected])
*/
public interface UserQueryService {

/**
* Yields an {@link Optional} containing the {@link User} document that is
* identified by the given <code>userId</code>. If no such {@link User} exists,
* the {@link Optional} does not carry any value.
*
* @param userId
* Identifies a {@link User} document
* @return
* {@link Optional} containing the {@link User} document
*/
Optional<User> getUserById(String userId);
}
Loading

0 comments on commit 4ed2de0

Please sign in to comment.