added security to picture upload resource
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Principal;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wildfly.security.auth.principal.NamePrincipal;
|
||||
import org.wildfly.security.auth.server.RealmUnavailableException;
|
||||
import org.wildfly.security.auth.server.SecurityDomain;
|
||||
import org.wildfly.security.auth.server.SecurityIdentity;
|
||||
import org.wildfly.security.evidence.PasswordGuessEvidence;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import javaslang.Tuple;
|
||||
import javaslang.Tuple2;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Jan 2026
|
||||
*/
|
||||
|
||||
public class LoginUtils {
|
||||
private static final Log LOG = LogFactory.getLog(LoginUtils.class);
|
||||
private static final int BASIC_HEADER_SIZE = 6;
|
||||
private static final int USERPASS_LENGTH = 1;
|
||||
|
||||
public Optional<SecurityIdentity> authenticate(HttpServletRequest httpServletRequest) {
|
||||
Tuple2<String, String> userPass = extractUsernamePassword(httpServletRequest);
|
||||
if (userPass._1.isBlank() || userPass._2.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return authenticate(userPass._1, userPass._2);
|
||||
}
|
||||
|
||||
public Optional<String> getSecurityToken(HttpServletRequest httpServletRequest) {
|
||||
Optional<String[]> headerOpt = extractAuthHeader(httpServletRequest);
|
||||
if (headerOpt.isPresent() && headerOpt.get().length > 2) {
|
||||
return Optional.ofNullable(headerOpt.get()[2]);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<SecurityIdentity> authenticate(String username, String password) {
|
||||
try {
|
||||
Principal principal = new NamePrincipal(username);
|
||||
PasswordGuessEvidence evidence = new PasswordGuessEvidence(password.toCharArray());
|
||||
|
||||
SecurityDomain sd = SecurityDomain.getCurrent();
|
||||
return Optional.ofNullable(sd.authenticate(principal, evidence));
|
||||
} catch (RealmUnavailableException | SecurityException e) {
|
||||
LOG.warn("Failed to authenticate user " + e.getMessage(), e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple2<String, String> extractUsernamePassword(HttpServletRequest httpServletRequest) {
|
||||
Optional<String[]> userPassOptional = extractAuthHeader(httpServletRequest);
|
||||
|
||||
if (userPassOptional.isPresent() && userPassOptional.get().length >= USERPASS_LENGTH) {
|
||||
String[] userpass = userPassOptional.get();
|
||||
String username = userpass[0];
|
||||
String password = userpass.length > USERPASS_LENGTH ? userpass[1] : "";
|
||||
|
||||
return Tuple.of(username, password);
|
||||
}
|
||||
return Tuple.of("", "");
|
||||
}
|
||||
|
||||
private Optional<String[]> extractAuthHeader(HttpServletRequest httpServletRequest) {
|
||||
Optional<String[]> retVal = Optional.empty();
|
||||
|
||||
String authorization = httpServletRequest.getHeader("Authorization");
|
||||
if (authorization != null && StringUtils.length(authorization) > BASIC_HEADER_SIZE) {
|
||||
authorization = authorization.substring(BASIC_HEADER_SIZE);
|
||||
String decoded = StringUtils.toEncodedString(Base64.decodeBase64(authorization), Charset.forName("utf-8"));
|
||||
retVal = Optional.of(decoded.split(":"));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract device information from User-Agent header
|
||||
*
|
||||
* @param request HTTP servlet request
|
||||
* @return Device/browser information
|
||||
*/
|
||||
public String extractDeviceInfo(HttpServletRequest request) {
|
||||
String userAgent = request.getHeader("User-Agent");
|
||||
return userAgent != null ? userAgent : "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract client IP address, considering proxies
|
||||
*
|
||||
* @param request HTTP servlet request
|
||||
* @return Client IP address
|
||||
*/
|
||||
public String extractIpAddress(HttpServletRequest request) {
|
||||
String xForwardedFor = request.getHeader("X-Forwarded-For");
|
||||
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
|
||||
// X-Forwarded-For can contain multiple IPs, take the first one
|
||||
return xForwardedFor.split(",")[0].trim();
|
||||
}
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,27 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.rest;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jboss.resteasy.annotations.GZIP;
|
||||
import org.wildfly.security.auth.server.SecurityIdentity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import jakarta.ejb.EJB;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.service.CustomerPictureService;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.LoginUtils;
|
||||
import marketing.heyday.hartmann.fotodocumentation.rest.jackson.JsonSchemaValidate;
|
||||
import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue;
|
||||
|
||||
@@ -28,18 +37,28 @@ import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue;
|
||||
@RequestScoped
|
||||
@Path("customer-picture")
|
||||
public class CustomerPictureResource {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(CustomerPictureResource.class);
|
||||
|
||||
@EJB
|
||||
private CustomerPictureService customerPictureService;
|
||||
|
||||
@Inject
|
||||
private LoginUtils loginUtils;
|
||||
|
||||
@GZIP
|
||||
@POST
|
||||
@Path("")
|
||||
//@Authenticate(shouldBeInAllRoles = RightUtils.ADMIN_RIGHT)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Add Customer Image to database")
|
||||
@ApiResponse(responseCode = "200", description = "Add successfull")
|
||||
public Response doAddCustomerPicture(@JsonSchemaValidate("schema/customer_picture_add.json") CustomerPictureValue customerPictureValue) {
|
||||
public Response doAddCustomerPicture(@Context HttpServletRequest httpServletRequest, @JsonSchemaValidate("schema/customer_picture_add.json") CustomerPictureValue customerPictureValue) {
|
||||
Optional<SecurityIdentity> identity = loginUtils.authenticate(httpServletRequest);
|
||||
if (identity.isEmpty()) {
|
||||
LOG.debug("identity empty login invalid");
|
||||
return Response.status(401).build();
|
||||
}
|
||||
|
||||
|
||||
boolean success = customerPictureService.addCustomerPicture(customerPictureValue);
|
||||
|
||||
return success ? Response.ok().build() : Response.status(Status.BAD_REQUEST).build();
|
||||
|
||||
Reference in New Issue
Block a user