Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ public ResponseEntity<JwtResponse> signIn(@Valid @RequestBody LoginRequest login
.collect(Collectors.toList());

Cookie jwtTokenCookie = new Cookie("jwtToken", jwt);
jwtTokenCookie.setSecure(false);
jwtTokenCookie.setHttpOnly(false);
jwtTokenCookie.setSecure(true);
jwtTokenCookie.setHttpOnly(true);
response.addCookie(jwtTokenCookie);

RefreshToken refreshToken = refreshTokenService.createRefreshToken(user.getId());
Expand Down Expand Up @@ -287,5 +287,3 @@ public ResponseEntity<RefreshTokenResponse> refreshToken(@Valid @RequestBody Ref
}

}


Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ protected void configure(HttpSecurity httpSecurity) throws Exception {
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//.and().httpBasic().authenticationEntryPoint(basicAuthenticationEntryPoint)
.and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler)
.and().csrf().disable();
.and().csrf().disable()
.headers()
.contentSecurityPolicy("default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'");

httpSecurity.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

Expand All @@ -145,7 +147,7 @@ protected void configure(HttpSecurity httpSecurity) throws Exception {
if (activeProfile.contains("dev")) {
log.info("Running development profile");
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
// Frame options protection enabled (using Spring Security defaults)
httpSecurity.cors().disable();
httpSecurity.headers().xssProtection().disable();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void handle(HttpServletRequest request, HttpServletResponse response, Acc
throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
ArrayList<String> errors = new ArrayList<>();
errors.add(ex.getLocalizedMessage());
errors.add("Access denied. You do not have permission to access this resource.");
ApiStatusResponse apiStatusResponse = new ApiStatusResponse
.ApiResponseBuilder()
.withSuccess(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void commence(HttpServletRequest request, HttpServletResponse response,
//response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ArrayList<String> errors = new ArrayList<>();
errors.add(ex.getLocalizedMessage());
errors.add("Authentication failed. Please check your credentials.");
ApiStatusResponse apiStatusResponse = new ApiStatusResponse
.ApiResponseBuilder()
.withSuccess(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,49 @@ public static String getTargetUrl(HttpServletRequest request, HttpServletRespons
log.debug("No loginReferer; redirecting to users home page");
targetUrl = USER_HOME_URL;
} else {
targetUrl = loginReferer;
String targetPath = null;
try {
targetPath = new URL(targetUrl).getPath();
URL url = new URL(loginReferer);
// Validate that the URL is from the same host
String requestHost = request.getServerName();
String refererHost = url.getHost();
if (refererHost != null && !refererHost.equals(requestHost)) {
log.warn("Referer host mismatch. Expected: " + requestHost + ", Got: " + refererHost);
targetUrl = USER_HOME_URL;
} else {
targetPath = url.getPath();
targetUrl = targetPath;
if (targetUrl.contains("?")) targetUrl = targetUrl.substring(0, targetUrl.indexOf("?"));
if (targetPath.endsWith("/cart")) {
targetUrl = targetUrl.replace("/cart", "/cart/checkout");
} else if (targetPath.endsWith("/login")) {
targetUrl = targetUrl.replace("/login", "/user");
} else if (targetPath.endsWith("/register")) {
targetUrl = targetUrl.replace("/register", "/");
} else if (targetPath.equals("/")) {
targetUrl = targetUrl + "user";
}
}
} catch (MalformedURLException ex) {
log.error(ex.getLocalizedMessage());
// If URL is malformed, treat as relative path
targetPath = loginReferer;
if (targetPath.startsWith("/")) {
targetUrl = targetPath;
if (targetUrl.contains("?")) targetUrl = targetUrl.substring(0, targetUrl.indexOf("?"));
if (targetPath.endsWith("/cart")) {
targetUrl = targetUrl.replace("/cart", "/cart/checkout");
} else if (targetPath.endsWith("/login")) {
targetUrl = targetUrl.replace("/login", "/user");
} else if (targetPath.endsWith("/register")) {
targetUrl = targetUrl.replace("/register", "/");
} else if (targetPath.equals("/")) {
targetUrl = targetUrl + "user";
}
} else {
targetUrl = USER_HOME_URL;
}
}
if (targetUrl.contains("?")) targetUrl = targetUrl.substring(0, targetUrl.indexOf("?"));
if (targetPath.endsWith("/cart")) {
targetUrl = targetUrl.replace("/cart", "/cart/checkout");
} else if (targetPath.endsWith("/login")) {
targetUrl = targetUrl.replace("/login", "/user");
} else if (targetPath.endsWith("/register")) {
targetUrl = targetUrl.replace("/register", "/");
} else if (targetPath.equals("/")) {
targetUrl = targetUrl + "user";
}

}
}
return targetUrl;
Expand Down Expand Up @@ -154,4 +179,4 @@ protected RedirectStrategy getRedirectStrategy() {
protected void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,39 @@ protected void handle(HttpServletRequest request,

boolean isUser = false;
boolean isAdmin = false;
String targetUrl = request.getParameter("referer");
//if (targetUrl.endsWith("/")) targetUrl = targetUrl.substring(0, targetUrl.length());
String targetPath = new URL(targetUrl).getPath();
String refererParam = request.getParameter("referer");
String targetUrl = "/";
String targetPath = "/";

// Validate referer is a relative path or same-origin URL
if (refererParam != null && !refererParam.isEmpty()) {
try {
if (refererParam.startsWith("/")) {
// Relative path - safe to use
targetPath = refererParam;
targetUrl = refererParam;
} else {
// Absolute URL - validate it's same origin
URL refererUrl = new URL(refererParam);
URL requestUrl = new URL(request.getRequestURL().toString());
if (refererUrl.getHost().equals(requestUrl.getHost()) &&
refererUrl.getProtocol().equals(requestUrl.getProtocol()) &&
refererUrl.getPort() == requestUrl.getPort()) {
targetPath = refererUrl.getPath();
targetUrl = refererParam;
} else {
// External URL - reject and use default
log.warn("Rejecting external referer URL: " + refererParam);
targetPath = "/";
targetUrl = "/";
}
}
} catch (Exception e) {
log.warn("Invalid referer URL: " + refererParam, e);
targetPath = "/";
targetUrl = "/";
}
}

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public int count() {
}

public List<Product> findAll(int offset, int limit) {
String sqlQuery = "select * from products" +
" LIMIT " + limit + " OFFSET " + offset;
return jdbcTemplate.query(sqlQuery, new ProductMapper());
String sqlQuery = "select * from products LIMIT ? OFFSET ?";
return jdbcTemplate.query(sqlQuery, new ProductMapper(), limit, offset);
}
}

public List<Product> findAvailable(int offset, int limit) {
Expand Down Expand Up @@ -91,8 +91,8 @@ public Optional<Product> findByCode(String code) {
List<Product> result = new ArrayList<>();
String query = code.toLowerCase();
String sqlQuery = "SELECT * FROM " + getTableName() +
" WHERE lower(code) = '" + query + "'";
result = jdbcTemplate.query(sqlQuery, new ProductMapper());
" WHERE lower(code) = ?";
result = jdbcTemplate.query(sqlQuery, new ProductMapper(), query);
Optional<Product> optionalProduct = Optional.empty();
if (!result.isEmpty()) {
optionalProduct = Optional.of(result.get(0));
Expand All @@ -110,12 +110,13 @@ public List<Product> findByKeywords(String keywords, int offset, int limit) {
return jdbcTemplate.query(sqlQuery, new ProductMapper());
}

public List<Product> findByKeywordsFromProductName(String keywords) {
String query = keywords.toLowerCase();
String sqlQuery = "SELECT * FROM " + getTableName() +
" WHERE lower(name) LIKE '%" + query + "%' ";
return jdbcTemplate.query(sqlQuery, new ProductMapper());
}
public List<Product> findByKeywordsFromProductName(String keywords) { // L113
String query = keywords.toLowerCase(); // L114
String sqlQuery = "SELECT * FROM " + getTableName() + // L115
" WHERE lower(name) LIKE ?"; // L116
String likePattern = "%" + query + "%"; // L117
return jdbcTemplate.query(sqlQuery, new ProductMapper(), likePattern); // L118
} // L119

public List<Product> findAvailableByKeywords(String keywords, int offset, int limit) {
String query = keywords.toLowerCase();
Expand All @@ -129,10 +130,10 @@ public List<Product> findAvailableByKeywords(String keywords, int offset, int li
}

public List<Product> findAvailableByKeywordsFromProductName(String keywords) {
String query = keywords.toLowerCase();
String sqlQuery = "SELECT * FROM " + getTableName() +
" WHERE available = true AND lower(name) LIKE '%" + query + "%' ";
return jdbcTemplate.query(sqlQuery, new ProductMapper());
String query = "%" + keywords.toLowerCase() + "%";
String sqlQuery = "SELECT * FROM " + getTableName() +
" WHERE available = true AND lower(name) LIKE ?";
return jdbcTemplate.query(sqlQuery, new ProductMapper(), query);
}

public Product save(Product p) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,11 @@ public Stream<Path> loadAll() {

@Override
public Path load(String filename) {
return rootLocation.resolve(filename);
Path resolvedPath = rootLocation.resolve(filename).normalize().toAbsolutePath();
if (!resolvedPath.getParent().equals(this.rootLocation.toAbsolutePath())) {
throw new StorageException("Cannot access file outside current directory.");
}
return resolvedPath;
}

@Override
Expand All @@ -156,9 +160,12 @@ public Resource loadAsResource(String filename, boolean traverse) {
try {
Path file = null;
if (traverse) {
file = Paths.get(filename);
file = rootLocation.resolve(filename).normalize();
if (!file.startsWith(rootLocation.toAbsolutePath().normalize())) {
throw new StorageException("Cannot access file outside current directory.");
}
} else {
file = load(filename);
file = load(filename);
}

Resource resource = new UrlResource(file.toUri());
Expand All @@ -173,7 +180,7 @@ public Resource loadAsResource(String filename, boolean traverse) {
}
catch (MalformedURLException e) {
throw new StorageFileNotFoundException("Could not read file: " + filename, e);
}
}
}

@Override
Expand Down
37 changes: 20 additions & 17 deletions src/main/java/com/microfocus/example/utils/UserUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ public static void writeUser(String username, String password) throws IOExceptio
jGenerator.writeStartObject();

jGenerator.writeFieldName("username");
jGenerator.writeRawValue("\"" + username + "\"");
jGenerator.writeString(username);

jGenerator.writeFieldName("password");
jGenerator.writeRawValue("\"" + password + "\"");
jGenerator.writeString(password);

jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"default\"");
jGenerator.writeString("default");

jGenerator.writeEndObject();

Expand All @@ -78,7 +78,9 @@ public static void registerUser(String firstName, String lastName, String email)

File dataFile = new File(getFilePath(NEWSLETTER_USER_FILE));
if (dataFile.exists()) {
jsonArray = (JSONArray) jsonParser.parse(new FileReader(getFilePath(NEWSLETTER_USER_FILE)));
try (FileReader reader = new FileReader(getFilePath(NEWSLETTER_USER_FILE))) {
jsonArray = (JSONArray) jsonParser.parse(reader);
}
} else {
dataFile.createNewFile();
log.debug("Created: " + getFilePath(NEWSLETTER_USER_FILE));
Expand All @@ -94,27 +96,27 @@ public static void registerUser(String firstName, String lastName, String email)
jGenerator.writeStartObject();
JSONObject person = (JSONObject) jsonObject;
jGenerator.writeFieldName("firstName");
jGenerator.writeRawValue("\"" + (String) person.get("firstName") + "\"");
jGenerator.writeString((String) person.get("firstName"));
jGenerator.writeFieldName("lastName");
jGenerator.writeRawValue("\"" + (String) person.get("lastName") + "\"");
jGenerator.writeString((String) person.get("lastName"));
jGenerator.writeFieldName("email");
jGenerator.writeRawValue("\"" + (String) person.get("email") + "\"");
jGenerator.writeString((String) person.get("email"));
jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"" + (String) person.get("role") + "\"");
jGenerator.writeString((String) person.get("role"));
jGenerator.writeEndObject();

}

// write new user
jGenerator.writeStartObject();
jGenerator.writeFieldName("firstName");
jGenerator.writeRawValue("\"" + firstName + "\"");
jGenerator.writeString(firstName);
jGenerator.writeFieldName("lastName");
jGenerator.writeRawValue("\"" + lastName + "\"");
jGenerator.writeString(lastName);
jGenerator.writeFieldName("email");
jGenerator.writeRawValue("\"" + email + "\"");
jGenerator.writeString(email);
jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"" + DEFAULT_ROLE + "\"");
jGenerator.writeString(DEFAULT_ROLE);
jGenerator.writeEndObject();

jGenerator.writeEndArray();
Expand All @@ -126,11 +128,12 @@ public static void registerUser(String firstName, String lastName, String email)

public void logZipContents(String fName)
throws IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
@SuppressWarnings("unchecked")
Enumeration<ZipEntry> e = (Enumeration<ZipEntry>) zf.entries();
while (e.hasMoreElements()) {
log.info(e.nextElement().toString());
try (ZipFile zf = new ZipFile(fName)) {
@SuppressWarnings("unchecked")
Enumeration<ZipEntry> e = (Enumeration<ZipEntry>) zf.entries();
while (e.hasMoreElements()) {
log.info(e.nextElement().toString());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,16 @@ String GetControllerName() {
@GetMapping("/xss")
@ResponseBody
public ResponseEntity<String> getKeywordsContent(@Param("keywords") String keywords) {

String retContent = "Product search using: " + keywords;

String encodedKeywords = keywords != null ?
keywords.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
.replace("'", "&#x27;") : "";
String retContent = "Product search using: " + encodedKeywords;
return ResponseEntity.ok().body(retContent);
}
}

@GetMapping("/firstaid")
public String firstaid(Model model, @Param("keywords") String keywords, @Param("limit") Integer limit, Principal principal) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,9 +669,10 @@ public ResponseEntity<?> serveUnverifiedFile(@Param("file") String file) {
return ResponseEntity.badRequest().build();
}

Resource rfile = storageService.loadAsResource(file, true);
Resource rfile = storageService.loadAsResource(file, true);
String sanitizedFilename = rfile.getFilename().replaceAll("[\\r\\n]", "");
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + rfile.getFilename() + "\"").body(rfile);
"attachment; filename=\"" + sanitizedFilename + "\"").body(rfile);
}

@GetMapping("/log")
Expand Down
Loading