Post Request return 404 for Spring Boot with Postman - spring

I am trying to use postman to test one of the post requests I created for my spring boot application. My post requests through postman always return 404.
I have created a same mapping route for a get request and with the postman, the get request works as expected.
I have tested with aws cli and made sure that I have the correct access key and secret key for uploading files to S3.
Code for my services
#Service
public class AmazonClient {
private AmazonS3 s3client;
#Value("${amazonProperties.endpointUrl}")
private String endpointUrl;
#Value("${amazonProperties.bucketName}")
private String bucketName;
#Value("${amazonProperties.accessKey}")
private String accessKey;
#Value("${amazonProperties.secretKey}")
private String secretKey;
#PostConstruct
private void initializeAmazon() {
AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);
this.s3client = AmazonS3ClientBuilder.standard().withRegion(Regions.US_EAST_2).withCredentials(
new AWSStaticCredentialsProvider(credentials)).build();
}
#Async
public String uploadFile(MultipartFile multipartFile, boolean enablePublicReadAccess) {
String fileUrl = "";
System.out.println("Reach");
try {
File file = convertMultiPartToFile(multipartFile);
String fileName = generateFileName(multipartFile);
System.out.println("FileName: " + fileName);
fileUrl = endpointUrl + "/" + bucketName + "/" + fileName;
PutObjectRequest putObjectRequest = new PutObjectRequest(this.bucketName, fileName, file);
if (enablePublicReadAccess) {
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead);
}
s3client.putObject(putObjectRequest);
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
return fileUrl;
}
private File convertMultiPartToFile(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
private String generateFileName(MultipartFile multiPart) {
return new Date().getTime() + "-" + multiPart.getOriginalFilename().replace(" ", "_");
}
public String deleteFileFromS3Bucket(String fileUrl) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
s3client.deleteObject(new DeleteObjectRequest(bucketName, fileName));
return "Successfully deleted";
}
}
Code for my controller:
#RestController
#RequestMapping("/storage/files")
public class BucketController {
private AmazonClient amazonClient;
#Autowired
BucketController(AmazonClient amazonClient) {
this.amazonClient = amazonClient;
}
#GetMapping
public String getFile(){
return "Files";
}
#PostMapping("/file")
public String file() {
return "Reach!";
}
#PostMapping
public String uploadFile(#RequestPart(value = "file") MultipartFile file) {
System.out.println("Reach!!");
return this.amazonClient.uploadFile(file, true);
}
#DeleteMapping
public String deleteFile(#RequestPart(value = "url") String fileUrl) {
return this.amazonClient.deleteFileFromS3Bucket(fileUrl);
}
}
My security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/css/**", "/js/**", "/fonts/**", "/index").permitAll()
.antMatchers("/storage*").permitAll();
Through postman, I have selected a POST request and put http://localhost:8080/storage/files/file, in the body, I have entered a key "file" and set the value to a file type and chose a file from my local.
Here is the response:
{
"timestamp": "2019-09-02T19:09:54.864+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/storage/files/file"
}
Project Structure
Postman Results

This is almost certainly your security config interfering.
Have you tried: .antMatchers("/storage/**") instead?

Related

AWS S3 uploaded file was not shown on cyberduck

I am trying to write an API for uploading and downloading files. After I uploaded a test file, it was not shown on cyberduck, but I can download the test file that I just uploaded.
Then I try to download the file that exist on cyberduck, but it shows
com.emc.object.s3.S3Exception: The specified key does not exist.
API code:
StorageImpl.java
#Service
public class StorageImpl implements Storage {
private static Logger logger = LoggerFactory.getLogger(Storage.class);
#Value("${storage.file.repository}")
private String fileRepository;
#Value("${object.storage.user}")
private String oUser;
#Value("${object.storage.endpoint}")
private String endpoint;
#Value("${object.storage.bucket}")
private String nBucket;
#Value("${object.storage.key.secret}")
private String nSecret;
#Value("${object.storage.region.name}")
private String nRegion;
private S3Client s3client;
public StorageImpl() {
}
#Inject
void init() {
try {
s3client = this.getS3Client();
} catch (Exception e) {
e.printStackTrace();
}
}
private S3Client getS3Client() {
if (s3client == null) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(new PreferredCipherSuiteSSLSocketFactory(sc.getSocketFactory()));
String hostname = "";
URI uri = null;
try {
uri = new URI(endpoint);
hostname = uri.getHost();
} catch (URISyntaxException e) {
logger.error("URL " + endpoint + " is a malformed URL");
e.printStackTrace();
}
S3Config config = null;
config = new S3Config(new URI(endpoint)).withUseVHost(false);
logger.debug("oUser=" + oUser + ", secret=" + nSecret + ", endpoint=" + endpoint);
config.withIdentity(oUser).withSecretKey(nSecret);
logger.debug("");
config.setSignMetadataSearch(true);
s3client = new S3JerseyClient(config, new URLConnectionClientHandler());
logger.debug("s3client initiated. endpoint: " + endpoint);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
return s3client;
}
private File convertMultiPartFileToFile(final MultipartFile multipartFile) {
final File file = new File(multipartFile.getOriginalFilename());
try (final FileOutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(multipartFile.getBytes());
} catch (IOException e) {
logger.error("Error {} occurred while converting the multipart file", e.getLocalizedMessage());
}
return file;
}
#Override
public void save(final MultipartFile multipartFile) {
try {
final File file = convertMultiPartFileToFile(multipartFile);
logger.info("Uploading file with name {}", file.getName());
final PutObjectRequest putObjectRequest = new PutObjectRequest(nBucket, file.getName(), file);
s3client.putObject(putObjectRequest);
Files.delete(file.toPath()); // Remove the file locally created in the project folder
} catch (AmazonServiceException e) {
logger.error("Error {} occurred while uploading file", e.getLocalizedMessage());
} catch (IOException ex) {
logger.error("Error {} occurred while deleting temporary file", ex.getLocalizedMessage());
}catch(S3Exception ae){
ae.printStackTrace();
logger.error("", ae);
}
}
#Override
public InputStream retrieve(String fileName) {
return s3client.getObject(nBucket, fileName).getObject();
}
}
FileController.java
#RestController
#RequestMapping("/files")
#CrossOrigin(origins = "*", maxAge = 3600)
public class FileController {
private static final String MESSAGE_1 = "Uploaded the file successfully";
private static final String FILE_NAME = "fileName";
#Autowired
protected StorageImpl storageImpl;
#Autowired
protected FileService fileService;
#GetMapping
public ResponseEntity<Object> findByName(#RequestParam("fileName") String fileName) {
return ResponseEntity
.ok()
.cacheControl(CacheControl.noCache())
.header("Content-type", "application/octet-stream")
.header("Content-disposition", "attachment; filename=\"" + fileName + "\"")
.body(new InputStreamResource(storageImpl.retrieve(fileName)));
}
#PostMapping
public ResponseEntity<Object> save(#RequestParam("file") MultipartFile multipartFile) {
storageImpl.save(multipartFile);
return new ResponseEntity<>(MESSAGE_1, HttpStatus.OK);
}
}
What are the possible reasons causing this bug?

JWT Reading private key in Spring

I have this service class that reads a private key from the classpath. The class is as follows:
#Component
#RequiredArgsConstructor
public class JwtKeyProvider {
private final ResourceUtil resourceUtil;
private final Base64Util base64Util;
#Getter
private PrivateKey privateKey;
#PostConstruct
public void init() {
privateKey = readKey(
"classpath:keys/scbpeopleintranetdev_sha1withrsa.pkcs8.private",
"PRIVATE",
this::privateKeySpec,
this::privateKeyGenerator
);
}
private <T extends Key> T readKey(String resourcePath, String headerSpec, Function<String, EncodedKeySpec> keySpec, BiFunction<KeyFactory, EncodedKeySpec, T> keyGenerator) {
try {
String keyString = resourceUtil.asString(resourcePath);
//TODO you can check the headers and throw an exception here if you want
keyString = keyString
.replace("-----BEGIN " + headerSpec + " KEY-----", "")
.replace("-----END " + headerSpec + " KEY-----", "")
.replaceAll("\\s+", "");
return keyGenerator.apply(KeyFactory.getInstance("RSA"), keySpec.apply(keyString));
} catch(NoSuchAlgorithmException | IOException e) {
throw new JwtInitializationException(e);
}
}
private EncodedKeySpec privateKeySpec(String data) {
return new PKCS8EncodedKeySpec(base64Util.decode(data));
}
private PrivateKey privateKeyGenerator(KeyFactory kf, EncodedKeySpec spec) {
try {
return kf.generatePrivate(spec);
} catch(InvalidKeySpecException e) {
throw new JwtInitializationException(e);
}
}
}
The thing is that my key is in the .key format, not in the .pkcs8 so I'm dealing with this console error:
java.security.InvalidKeyException: IOException : algid parse error, not a sequence
I've tried out converting it to pkcs8 and it works but any one knows how to solve this code avoiding converting it to pkcs8?
Thanks in advance!

Spring Boot - Upload files on Remote Machine

I want to upload file on remote server, currently i am only able to upload on local machine. below is my code
#PostMapping("/upload")
public UploadFileResponse uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
return new UploadFileResponse(fileName, fileDownloadUri,file.getContentType(), file.getSize());
}
file.upload-dir=C:\\Test
Thanks in Advance!
EDIT:
1. Use case : You want to upload the file locally (i.e. where your application is running):
You create StorageService interface and an implementing class FileSystemStorageService:
#Service
public class FileSystemStorageService implements StorageService {
private final Path rootLocation;
#Autowired
public FileSystemStorageService(StorageProperties properties) {
this.rootLocation = Paths.get(properties.getLocation());
}
#Override
public void store(MultipartFile file) {
String filename = StringUtils.cleanPath(file.getOriginalFilename());
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file " + filename);
}
if (filename.contains("..")) {
// This is a security check
throw new StorageException(
"Cannot store file with relative path outside current directory "
+ filename);
}
try (InputStream inputStream = file.getInputStream()) {
Files.copy(inputStream, this.rootLocation.resolve(filename),
StandardCopyOption.REPLACE_EXISTING);
}
}
catch (IOException e) {
throw new StorageException("Failed to store file " + filename, e);
}
}
And the controller class:
#Controller
public class FileUploadController {
private final StorageService storageService;
#Autowired
public FileUploadController(StorageService storageService) {
this.storageService = storageService;
}
#PostMapping("/")
public String handleFileUpload(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
You can find the whole sample under https://github.com/spring-guides/gs-uploading-files.
2. Use case : You want to upload the file to a remote server:
I recommend in this case to use SFTP.
You create a RemoteFileSystemStorageService implementing the StorageService (Already created in the first use case).
#Service
public class RemoteFileSystemStorageService implements StorageService {
#Autowired
private StorageProperties properties
final private ChannelSftp channelSftp;
#PostConstruct
public void setUpSsh(){
JSch jsch = new JSch();
Session jschSession = jsch.getSession(properties.getUsername(),
properties.getRemoteHost());
jschSession.setPassword(properties.getPassword());
jschSession.connect();
this.channelSftp = (ChannelSftp)jschSession.openChannel("sftp");
}
#Override
public void store(MultipartFile file) {
String filename = StringUtils.cleanPath(file.getOriginalFilename());
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file " + filename);
}
if (filename.contains("..")) {
// This is a security check
throw new StorageException(
"Cannot store file with relative path outside current directory "
+ filename);
}
try (InputStream inputStream = file.getInputStream()) {
this.channelSftp.connect();
this.channelSftp.put(inputStream, properties.getRemoteServerDirectory());
}
}
catch (IOException e) {
throw new StorageException("Failed to store file " + filename, e);
}
finally{
this.channelSftp.close();
}
}

Consuming Soap Service in spring boot application

I need to consume a soap service in spring boot. How can i do that easily using annotations like we do for Rest. I need to send headers, form the body for my service. Please help me with the solution
public String sendMessage(String processInstanceId) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
String request = "<SOAP:Envelope xmlns:" + "SOAP='http://schemas.xmlsoap.org/soap/envelope/'>" + "<SOAP:Body>"
+ "<SendMessage xmlns='http://schemas.cordys.com/bpm/execution/1.0'>" + "<receiver>" + processInstanceId
+ "</receiver>" + "<message overwrite='false' />" + "</SendMessage>" + "</SOAP:Body>"
+ "</SOAP:Envelope>";
SendMessageAPI sendMessageObject = new SendMessageAPI();
StreamSource source = new StreamSource(new StringReader(request));
StreamResult result = new StreamResult(System.out);
System.out.println("called service" + request);
webServiceTemplate.sendSourceAndReceiveToResult(
"url",
source, result);
return "Success";
You may use Spring Web Service where it's present the WebServiceTemplate similar to the RestTemplate
In order to add SOAP Header and/or HTTP Header you can implement the WebServiceMessageCallback interface.
Here a simple example for adding HTTP Headers
The WebServiceMessageCallback implementation (note I'm using Axiom as MessageFactory)
public class WsHttpHeaderCallback implements WebServiceMessageCallback
{
private String headerKey;
private String headerValue;
private String soapAction;
public WsHttpHeaderCallback(String headerKey, String headerValue, String soapAction)
{
super();
this.headerKey = headerKey;
this.headerValue = headerValue;
this.soapAction = soapAction;
}
public WsHttpHeaderCallback()
{
super();
}
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException
{
validateRequiredFields();
addRequestHeader(headerKey, headerValue);
if (StringUtils.hasText(this.soapAction))
{
AxiomSoapMessage axiomMessage = (AxiomSoapMessage) message;
axiomMessage.setSoapAction(this.soapAction);
}
}
private void addRequestHeader(String headerKey, String headerValue)
{
TransportContext context = TransportContextHolder.getTransportContext();
WebServiceConnection connection = context.getConnection();
if (connection instanceof HttpComponentsConnection)
{
HttpComponentsConnection conn = (HttpComponentsConnection) connection;
HttpPost post = conn.getHttpPost();
post.addHeader(headerKey, headerValue);
}
else if( connection instanceof ClientHttpRequestConnection )
{
ClientHttpRequestConnection conn = (ClientHttpRequestConnection)connection;
conn.getClientHttpRequest().getHeaders().add(headerKey, headerValue);
}
}
}
The WebServiceMessageCallback usage:
WebServiceResponse resp = (WebServiceResponse)webSvcTemplate.marshalSendAndReceive(wsUrl, request, new WsHttpHeaderCallback(headerKey, headerValue, "http://ws.com/soapAction") );
I hope it's usefull
Angelo

How to reproduce this cURL request using Spring RestTemplate?

I am trying to achieve GET request calls containing a request body. Yeah, I know. So here is my problem.
I have a Spring MVC controller responding fine to the following pseudo-command:
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:9098/a/{aID}/b/{bID}/c -d '{"header":{"foo":"foofoofoo","timestamp":"2015-06-23T03:45:43-04:00"}}'
I am trying to reproduce this call from another spring mvc app using RestTemplate.exchange, but keep getting a 400 bad request error on the client side app -- the server side application doesn't seem to log any error regarding the call.
The client side controller
#GET
#Produces(APPLICATION_JSON)
#Path("/a/{aID}/b/{bID}/c")
public String getC(
#PathParam(value = "aID") String aId,
#PathParam(value = "bID") String bId) {
ResponseEntity<String> result = null;
RestTemplate restTemplate = new RestTemplate();
StringBuilder url = new StringBuilder(serverApplicationUrlLocalhost9098);
url.append("/a/").append(aId);
url.append("/b/").append(bId);
url.append("/c");
String finalUrl = url.toString();
try {
org.springframework.http.MediaType mediaType = org.springframework.http.MediaType.APPLICATION_JSON;
List<org.springframework.http.MediaType> accepts = new ArrayList<org.springframework.http.MediaType>();
accepts.add(org.springframework.http.MediaType.APPLICATION_JSON);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(accepts);
headers.setContentType(mediaType);
Foo foo = new Foo();
HttpEntity<Foo> request = new HttpEntity<Foo>(foo, headers);
result = restTemplate.exchange(finalUrl, HttpMethod.GET, request, String.class);
} catch (Exception e) {
logger.error("Error calling REST service: " + finalUrl, e);
}
return result.getBody();
}
For the purpose of testing, I have a private class Foo
private class Header {
private String foo = "foofoofoo";
private String timestamp = "2015-06-23T03:45:43-04:00";
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}
private class Foo {
private Header header = new Header();
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
}

Resources