Skip to content
This repository has been archived by the owner on May 22, 2021. It is now read-only.

Commit

Permalink
Merge pull request #38 from E-Edu/issue/37
Browse files Browse the repository at this point in the history
Issue/37
  • Loading branch information
steve-hb authored Mar 28, 2020
2 parents e25372a + de681fb commit 1921abe
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 71 deletions.
14 changes: 6 additions & 8 deletions src/main/java/de/themorpheus/edu/gateway/GatewayApplication.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.themorpheus.edu.gateway;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
Expand All @@ -10,9 +9,6 @@
@SpringBootApplication
public class GatewayApplication {

@Value("${graphql.url:graphql}")
private static final String GRAPHQL_URL = "/graphql";

public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
Expand All @@ -22,10 +18,12 @@ public WebMvcConfigurer webConfiguration() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(GRAPHQL_URL).allowedOrigins(
"http://localhost:3000",
"api.e-edu.the-morpheus.de"
).allowedMethods("GET", "OPTION", "POST", "PATCH", "PUT", "DELETE");
registry
.addMapping("/graphql")
.allowedOrigins(
"*" //TODO: Not in production
)
.allowedMethods("GET", "OPTION", "POST", "PATCH", "PUT", "DELETE");
}
};
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package de.themorpheus.edu.gateway.graphql.resolver.mutation.user;

import de.themorpheus.edu.gateway.graphql.dto.user.JwtRequestDTO;
import de.themorpheus.edu.gateway.graphql.dto.user.JwtResultDTO;
import de.themorpheus.edu.gateway.graphql.dto.user.UserAuthDTO;
import de.themorpheus.edu.gateway.graphql.dto.user.UserAuthResultDTO;
import org.springframework.stereotype.Component;
import javax.servlet.http.Cookie;
import javax.validation.Valid;
import de.themorpheus.edu.gateway.graphql.resolver.util.HeaderUtil;
import de.themorpheus.edu.gateway.graphql.resolver.util.JsonWebToken;
import de.themorpheus.edu.gateway.graphql.resolver.util.RefreshToken;
import java.util.Map;
import java.util.Optional;
import java.time.Duration;
import java.util.UUID;
import graphql.kickstart.tools.GraphQLMutationResolver;
import graphql.schema.DataFetchingEnvironment;
Expand All @@ -19,19 +18,14 @@
public class AuthenticationResolver implements GraphQLMutationResolver {

public UserAuthResultDTO authenticate(@Valid UserAuthDTO userAuth, DataFetchingEnvironment environment) {
Optional<String> optionalDeviceId = HeaderUtil.findHeader(environment, HeaderUtil.DEVICE_ID);
String deviceId = HeaderUtil.getCookie(environment, HeaderUtil.DEVICE_ID);

deviceId: {
HeaderUtil.setCookie(
environment,
Map.of(
HeaderUtil.DEVICE_ID, optionalDeviceId.orElse("EXAMPLE_DEVICE_COOKIE"),
//HeaderUtil.CookieOption.SAME_SITE.getValue(), "Strict" //TODO: Activate
HeaderUtil.CookieOption.SAME_SITE.getValue(), "None"
),
HeaderUtil.CookieOption.SECURE,
HeaderUtil.CookieOption.HTTP_ONLY
);
Cookie cookie = new Cookie(HeaderUtil.DEVICE_ID, deviceId == null ? "EXAMPLE_DEVICE_COOKIE" : deviceId);
cookie.setHttpOnly(true);
cookie.setMaxAge((int) Duration.ofDays(365).toSeconds());
//cookie.setSecure(true); //TODO: Only in productive
HeaderUtil.addCookie(environment, cookie);
}

//TODO: Backend authentication
Expand All @@ -40,22 +34,20 @@ public UserAuthResultDTO authenticate(@Valid UserAuthDTO userAuth, DataFetchingE

if (resultType == UserAuthResultDTO.UserAuthResultType.SUCCESS) {
refreshToken: {
HeaderUtil.setCookie(
environment,
Map.of(
HeaderUtil.REFRESH_TOKEN, RefreshToken.generate(userId),
HeaderUtil.CookieOption.SAME_SITE.getValue(), "None" //TODO: Strict
),
HeaderUtil.CookieOption.SECURE,
HeaderUtil.CookieOption.HTTP_ONLY
);
Cookie cookie = new Cookie(HeaderUtil.REFRESH_TOKEN, RefreshToken.generate(userId));
cookie.setHttpOnly(true);
cookie.setMaxAge((int) Duration.ofDays(365).toSeconds());
//cookie.setSecure(true); //TODO: Only in productive

HeaderUtil.addCookie(environment, cookie);
//TODO: Same-Site?
}
}

return new UserAuthResultDTO(resultType);
}

public JwtResultDTO jwt(@Valid JwtRequestDTO requestDTO, DataFetchingEnvironment environment) {
public JwtResultDTO jwt(DataFetchingEnvironment environment) {
// Get cookie
String refreshTokenCookie = HeaderUtil.getCookie(environment, HeaderUtil.REFRESH_TOKEN);
if (refreshTokenCookie == null) return new JwtResultDTO(null, JwtResultDTO.JwtStatus.INVALID); //TODO: 403 Forbidden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;
import java.util.List;
import graphql.schema.DataFetchingEnvironment;
import graphql.servlet.context.DefaultGraphQLServletContext;

Expand All @@ -15,19 +16,20 @@ public class HeaderUtil {
public static final String DEVICE_ID = "device_id";
public static final String REFRESH_TOKEN = "refresh_token";

public static final String SET_COOKIE = "set-cookie";
public static final String COOKIE = "cookie";

public static Optional<String> findHeader(DataFetchingEnvironment environment, String header) {
public static List<String> findRequestHeader(DataFetchingEnvironment environment, String header) {
DefaultGraphQLServletContext context = environment.getContext();
HttpServletRequest request = context.getHttpServletRequest();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String currentHeader = headerNames.nextElement();
if (currentHeader.equalsIgnoreCase(header)) return Optional.of(request.getHeader(currentHeader));
Enumeration<String> headers = request.getHeaders(header);

List<String> result = new ArrayList<>();
while (headers.hasMoreElements()) {
String currentHeader = headers.nextElement();
result.add(currentHeader);
}

return Optional.empty();
return result;
}

public static void setHeader(DataFetchingEnvironment environment, String header, String value) {
Expand All @@ -36,35 +38,24 @@ public static void setHeader(DataFetchingEnvironment environment, String header,
response.setHeader(header, value);
}

public static void setCookie(DataFetchingEnvironment environment, Map<String, String> cookies, CookieOption... options) {
public static void addCookie(DataFetchingEnvironment environment, Cookie cookie) {
DefaultGraphQLServletContext context = environment.getContext();
HttpServletResponse response = context.getHttpServletResponse();
StringBuilder value = new StringBuilder();
cookies.forEach((cookieKey, cookieValue) -> {
value.append(cookieKey);
value.append('=');
value.append(cookieValue);
value.append(';');
});

for (CookieOption option : options) {
if (option.isValueRequired()) throw new IllegalArgumentException("Consider passing this option via 'cookies': " + option);
value.append(option.getValue());
value.append(';');
}

response.setHeader(SET_COOKIE, value.toString());
response.addCookie(cookie);
}

public static String getCookie(DataFetchingEnvironment environment, String key) {
Optional<String> cookieOptional = HeaderUtil.findHeader(environment, COOKIE);
if (!cookieOptional.isPresent()) return null;
List<String> cookiesList = HeaderUtil.findRequestHeader(environment, COOKIE);
if (cookiesList.isEmpty()) return null;

String[] parts = cookieOptional.get().split(";");
for (String cookies : cookiesList) {
for (String c : cookies.split(";")) {
String cookie = c.trim();

for (String part : parts)
if (part.startsWith(key) && part.contains("="))
return part.split("=")[1];
if (cookie.startsWith(key) && cookie.contains("="))
return cookie.split("=")[1];
}
}

return null;
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
security.basic.enable:false
security.basic.enable=false
server.port=80
graphql.playground.settings.request.credentials=Same-Origin
3 changes: 1 addition & 2 deletions src/main/resources/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Mutation {

authenticate(userAuth: UserAuth): UserAuthResult

jwt(jwtRequest: JwtRequest): JwtResult
jwt: JwtResult

}

Expand Down Expand Up @@ -126,7 +126,6 @@ enum UserAuthResultType {

# HTTP Secure Cookie: refresh_token
# HTTP Secure Cookie: device_id
input JwtRequest

type JwtResult {
token: String # JWT; ONLY stored in the frontend state manager!
Expand Down

0 comments on commit 1921abe

Please sign in to comment.