Skip to content

Commit

Permalink
Merge pull request #6 from KPMP/develop
Browse files Browse the repository at this point in the history
Release 0.1
  • Loading branch information
zwright authored May 29, 2019
2 parents a546308 + b635d18 commit db3dd83
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 27 deletions.
15 changes: 15 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
language: java

jdk:
- oraclejdk8

install: true

script:
- ./gradlew build

notifications:
email:
- [email protected]
- [email protected]
- [email protected]
43 changes: 18 additions & 25 deletions src/main/java/org/kpmp/auth/AuthController.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.kpmp.auth;

import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import static org.kpmp.auth.SecurityConstants.EXPIRATION_TIME;
import static org.kpmp.auth.SecurityConstants.SECRET;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
Expand All @@ -12,6 +10,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
Expand All @@ -34,20 +33,20 @@ public class AuthController {
private HttpSession session;
private ShibbolethUserService userService;
private UTF8Encoder encoder;
private TokenService tokenService;

@Autowired
public AuthController(ShibbolethUserService userService, UTF8Encoder encoder) {
public AuthController(ShibbolethUserService userService, UTF8Encoder encoder, TokenService tokenService) {
this.userService = userService;
this.encoder = encoder;
this.tokenService = tokenService;
}

@RequestMapping(value = "/login", method = RequestMethod.GET)
public @ResponseBody RedirectView login(HttpServletRequest request, HttpSession httpSession) throws UnsupportedEncodingException {
String redirectURL = request.getParameter("redirect");
session = httpSession;
User user = userService.getUser(request, encoder);
//Setting the userID to the session ID for now, but in the future this should probably come from a DB.
user.setId(session.getId());
session.setAttribute("user", user);
return new RedirectView(redirectURL);
}
Expand All @@ -56,29 +55,23 @@ public AuthController(ShibbolethUserService userService, UTF8Encoder encoder) {
@RequestMapping(value = "/auth")
public @ResponseBody AuthResponse getAuth(@RequestBody Map<String, Object> payload) throws IOException {
AuthResponse auth = new AuthResponse();
String token = (String) payload.get("token");
User user = new User();
if (session != null) {
user = (User) session.getAttribute("user");
token = JWT.create().withSubject(user.getId())
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.sign(HMAC512(SECRET.getBytes()));
auth.setToken(token);
auth.setUser((User) session.getAttribute("user"));
session = null;
} else if (token != null) {
try {
DecodedJWT verifiedToken = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
.build()
.verify(token);
String tokenString = (String) payload.get("token");
if (tokenString != null) {
DecodedJWT verifiedToken = tokenService.verifyToken(tokenString);
if (verifiedToken != null) {
auth.setToken(verifiedToken.getToken());
//In the future, grab the user from the DB based on the ID stored in the JWT subject.
user.setId(verifiedToken.getSubject());
auth.setUser(user);
} catch (JWTVerificationException exception) {
auth.setToken(null);
auth.setUser(tokenService.getUserFromToken(verifiedToken));
}
}

if (session != null && auth.getToken() == null) {
User user = (User) session.getAttribute("user");
tokenString = tokenService.buildTokenWithUser(user);
auth.setToken(tokenString);
auth.setUser(user);
session = null;
}

return auth;
}

Expand Down
25 changes: 23 additions & 2 deletions src/main/java/org/kpmp/auth/SecurityConstants.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
package org.kpmp.auth;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component
@Scope("singleton")
public class SecurityConstants {
public static final String SECRET = "TubuleGlomerulusNephron";
public static final long EXPIRATION_TIME = 28_800_000; // 8 hours

private final byte[] secret;
public static final long EXPIRATION_TIME = 28_800_000;

public SecurityConstants() {
Random random = new Random();
byte[] secret = new byte[32];
random.nextBytes(secret);
this.secret = secret;
}

public byte[] getSecret() {
return secret;
}

}
3 changes: 3 additions & 0 deletions src/main/java/org/kpmp/auth/ShibbolethUserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ public User getUser(HttpServletRequest request, UTF8Encoder encoder) throws Unsu
String firstName = encoder.convertFromLatin1(value);
value = handleNull(request.getHeader("sn"));
String lastName = encoder.convertFromLatin1(value);
value = handleNull(request.getHeader("eppn"));
String userId = encoder.convertFromLatin1(value);

User user = new User();
user.setDisplayName(displayName);
user.setLastName(lastName);
user.setFirstName(firstName);
user.setEmail(email);
user.setId(userId);
return user;

}
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/org/kpmp/auth/TokenService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.kpmp.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.stereotype.Service;
import users.User;

import java.io.IOException;
import java.util.Date;

import static com.auth0.jwt.algorithms.Algorithm.HMAC512;

@Service
public class TokenService {

private SecurityConstants securityConstants;

public TokenService(SecurityConstants securityConstants) {
this.securityConstants = securityConstants;
}

public String buildTokenWithUser(User user) throws JsonProcessingException {
return JWT.create().withSubject(user.getId())
.withExpiresAt(new Date(System.currentTimeMillis() + securityConstants.EXPIRATION_TIME)).withClaim("user", user.toJson())
.sign(HMAC512(securityConstants.getSecret()));
}

public DecodedJWT verifyToken(String token) {
try {
return JWT.require(Algorithm.HMAC512(securityConstants.getSecret()))
.build()
.verify(token);

} catch (JWTVerificationException exception) {
return null;
}
}

public User getUserFromToken(DecodedJWT verifiedToken) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(verifiedToken.getClaim("user").asString(), User.class);
} catch (IOException e) {
return null;
}
}

}
9 changes: 9 additions & 0 deletions src/main/java/users/User.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package users;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@JsonPropertyOrder({ "id", "firstName", "lastName", "displayName", "email" })
public class User {
Expand All @@ -11,6 +14,7 @@ public class User {
private String displayName;
private String email;

@JsonIgnore
public String getId() {
return id;
}
Expand Down Expand Up @@ -59,4 +63,9 @@ public String toString() {
", displayName: " + displayName +
", email: " + email;
}

public String toJson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(this);
}
}
8 changes: 8 additions & 0 deletions src/test/java/org/kpmp/auth/AuthResponseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import users.User;

public class AuthResponseTest {

Expand All @@ -27,5 +28,12 @@ public void testSetToken() throws Exception {
assertEquals("token", authResponse.getToken());
}

@Test
public void testSetUser() throws Exception {
User user = new User();
authResponse.setUser(user);
assertEquals(user, authResponse.getUser());
}


}
28 changes: 28 additions & 0 deletions src/test/java/org/kpmp/auth/SecurityConstantsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.kpmp.auth;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SecurityConstantsTest {

private SecurityConstants securityConstants;

@Before
public void setUp() throws Exception {
securityConstants = new SecurityConstants();
}

@After
public void tearDown() throws Exception {
securityConstants = null;
}

@Test
public void testGetSecret() {
assertEquals(securityConstants.getSecret().length, 32);
}

}
54 changes: 54 additions & 0 deletions src/test/java/org/kpmp/auth/TokenServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.kpmp.auth;

import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import users.User;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;

public class TokenServiceTest {

private TokenService tokenService;
@Mock
private SecurityConstants securityConstants;


@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
tokenService = new TokenService(securityConstants);
}

@After
public void tearDown() throws Exception {
tokenService = null;
}

@Test
public void testBuildandVerifyToken() throws Exception {
when(securityConstants.getSecret()).thenReturn("GiveMeTheInfinityStones".getBytes());
User user = new User();
user.setId("123");
user.setDisplayName("Thanos the Great");
user.setEmail("[email protected]");
user.setFirstName("Thanos");
user.setLastName("Smith");
String token = tokenService.buildTokenWithUser(user);
assertNotNull(token);
DecodedJWT verifiedToken = tokenService.verifyToken(token);
assertNotNull(verifiedToken);
User userFromJWT = tokenService.getUserFromToken(verifiedToken);
assertEquals(userFromJWT.getDisplayName(), user.getDisplayName());
assertEquals(userFromJWT.getEmail(), user.getEmail());
assertEquals(userFromJWT.getFirstName(), user.getFirstName());
assertEquals(userFromJWT.getLastName(), user.getLastName());
assertEquals(verifiedToken.getSubject(), user.getId());
}

}
13 changes: 13 additions & 0 deletions src/test/java/users/UserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,17 @@ public void testToString() {
", displayName: Space Oddity" +
", email: [email protected]", testUser.toString());
}

@Test
public void testToJson() throws Exception{
testUser.setId("12345");
testUser.setDisplayName("Space Oddity");
testUser.setFirstName("Ziggy");
testUser.setLastName("Stardust");
testUser.setEmail("[email protected]");
assertEquals("{\"firstName\":\"Ziggy\"" +
",\"lastName\":\"Stardust\"" +
",\"displayName\":\"Space Oddity\"" +
",\"email\":\"[email protected]\"}", testUser.toJson());
}
}

0 comments on commit db3dd83

Please sign in to comment.