Enable CORS On Spring accessing MongoDB data - spring

I'm trying to develop a RestFul Web Service with Spring, that fetches data from a mongoDB collection and serves it to a client. To build the service i followed this guide on spring.io. Everything went well, i can access data from mongoDB and search it for the data structure name.
The troubles began when i tried to manage requests from my client, i receive classical error of same-domain-policy violation.
No 'Access-Control-Allow-Origin' header is present on the requested
resource.
The project is EXTREMELY simple, is composed of those 3 classes:
Frames.java
#Id
private String Id;
private String frameName;
private ArrayList<String> frameElements;
public String getId() {
return Id;
}
public String getFrameName() {
return frameName;
}
public ArrayList<String> getFrameElements() {
return frameElements;
}
FrameRestFulServiceApplication.java
#SpringBootApplication
public class FrameRestFulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FrameRestFulServiceApplication.class, args);
}
}
FramesRepository.java
#RepositoryRestResource(collectionResourceRel = "frames", path = "frames")
public interface FramesRepository extends MongoRepository<Frames, String>{
List<Frames> findByFrameNameLike(#Param("frameName") String frameName);
List<Frames> findByFrameName(#Param("frameName") String frameName);
}
I tried different methods found in the documentation See here but without results...

A similar question is Spring Data Rest and Cors
The answer is that if you are using Spring Boot (which supports Filter beans), it could be something like:
#Configuration
public class RestConfiguration {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // you USUALLY want this
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

have you tried to add a class like this?
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
it worked for me

Related

required a bean of type 'org.springframework.cloud.netflix.ribbon.SpringClientFactory' that could not be found

I have this test project which I would like to migrate to more recent version:
#Configuration
public class LoadbalancerConfig extends RibbonLoadBalancerClient {
public LoadbalancerConfig(SpringClientFactory clientFactory) {
super(clientFactory);
}
}
Full code example: https://github.com/rcbandit111/Generic_SO_POC/blob/master/src/main/java/org/merchant/database/service/sql/LoadbalancerConfig.java
Do you know how I can migrate this code to latest load balancer version?
I think examining the RibbonAutoConfiguration class gives you a good hint of how you should configure things.
First remove #Configuration from LoadbalancerConfig, I also renamed LoadbalancerConfig to CustomLoadbalancer to prevent confusion.
public class CustomLoadbalancer extends RibbonLoadBalancerClient {
public CustomLoadbalancer(SpringClientFactory clientFactory) {
super(clientFactory);
}
}
add the following dependency to your gradle
com.netflix.ribbon:ribbon:2.7.18
then add a configuration class like:
#Configuration
#ConditionalOnClass({Ribbon.class})
#AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
#ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled",
havingValue = "true", matchIfMissing = true)
#AutoConfigureBefore(LoadBalancerAutoConfiguration.class)
public class LoadBalancerClientConfig {
#Autowired(required = false)
private List<RibbonClientSpecification> configurations = new ArrayList<>();
#Bean
public CustomLoadbalancer customLoadbalancer() {
return new CustomLoadbalancer(springClientFactory());
}
#Bean
public SpringClientFactory springClientFactory() {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
}
If you want to use Spring cloud load balancer instead of above configuration add spring-cloud-starter-loadbalancer dependency to your gradle.build and for configuration you only need this bean:
#LoadBalanced
#Bean
RestTemplate getRestTemplate() {
return new RestTemplate();
}
This RestTemplate pretty works identical to standard RestTemplate class, except instead of using physical location of the service, you need to build the URL using Eureka service ID.
Here is an example of how could you possibly use it in your code
#Component
public class LoadBalancedTemplateClient {
#Autowired
RestTemplate restTemplate;
#Autowired
User user;
public ResponseEntity<Result> getResult() {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder
.fromHttpUrl("http://application-id/v1/") // application id registered in eureka
.queryParam("id", user.getUserId());
return restTemplate.getForEntity(uriComponentsBuilder.toUriString(),
Result.class);
}
}
Also if you wish to use reactive client the process is the same first define the bean:
#LoadBalanced
#Bean
WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
and then inject and use it when you need:
#Autowired
private WebClient.Builder webClient;
public Mono<String> doSomething() {
return webClient
.build()
.get()
.uri("http://application-id/v1/")
.retrieve()
.bodyToMono(String.class);
}
Also you can check documentation for additional information: documentation

spring security, get methods and url from table and validate the authorizeRequests dinamicly

I have this to validate the method and resouce and role but I can not believe that this part need to set in code, exist a way to consult a table?
For example
table: user_access <br>
campos: url , path <br>
method="HttpMethod.GET" <br>
path="/api/clientes/page/**"
And I have this code:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
//implementar reglas de seguridad para los end points
//por el lado de oauth
#Override
public void configure(HttpSecurity http) throws Exception {
//reglas especificate al mas generico
**//I Dont like this part and i try to creat it dinamicly**
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/clientes","/api/clientes/page/*","/api/clientes/img/*","/images/**").permitAll()
.antMatchers(HttpMethod.GET,"/api/clientes/form/").hasAnyRole("ADMIN","SUPER_ADMIN")
.antMatchers(HttpMethod.POST,"/api/clientes/uploads").hasAnyRole("ADMIN","SUPER_ADMIN")
.antMatchers(HttpMethod.POST,"/api/clientes").hasAnyRole("ADMIN","SUPER_ADMIN")
.antMatchers(HttpMethod.DELETE,"/api/clientes/{id}").hasRole("SUPER_ADMIN")
.antMatchers(HttpMethod.GET,"/api/clientes/{id}").hasRole("SUPER_ADMIN")
.anyRequest().authenticated()
.and().cors().configurationSource(cousConfigurationSource()); //error en el cors con esto se arregla para la pagina de angular
}
//importante no tomar cors.reactive
#Bean
public CorsConfigurationSource cousConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS")); //se podria poner * para todo
config.setAllowCredentials(true);
config.setAllowedHeaders(Arrays.asList("Content-Type","Autorization"));
UrlBasedCorsConfigurationSource source= new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
//filtro //seleccionar spring Framework
#Bean
public FilterRegistrationBean<CorsFilter> corsFilter(){
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(cousConfigurationSource()));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
Any Idea to make it more dynamic?
Hope below will help,
You can do it but it will work when the application starts, You can create a table to hold all of required configs, and when the application start running, you can write a code to read all of configured values and use them to configure the HttpSecurity.
Example:
#Entity
public class UserAccessEntity{
#Id
private String url;
private String methodName;
private List<String> userRoles;
private boolean isPattern;
// setter and getter
}
public interface UserAccessRepository extends CrudRepository<UserAccessEntity,String> {}
Then just do the configuration after you fetch the records from the database as below:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final UserAccessRepository repository;
public ResourceServerConfig(UserAccessRepository repository){
this.repository = repository;
}
// Configure this as you need.
#Override
public void configure(HttpSecurity http) throws Exception {
repository.findAll().foreach(userAccess -> {
http.authorizeRequests()
.antMatchers(userAccess.getMethodName(),userAccess.getUrl())
.hasAnyRole(userAccess.getRoles())
});
}
}
Only the limitation you have is that you can pre-configure all of the access before application get started, and you have to restart the server if you need to reflect any change of the user access records.
I think #PreAuthorize can make your validation more dynamically: You can validate for your controller, and using spEL(Spring expression language) to combine more cases.
To enable #PreAuthorize, you need to config in the WebSecurityConfig
#Configuration
#EnableWebSecurity
//enable for #PreAuthorize
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSercurityConfig extends WebSecurityConfigurerAdapter {
//configs
}
In my example, the 'SUPER_ADMIN' or user who owned the resources can access the data from the request(get the user details information). Hope this can be helpful for you.
#RestController
public class UserDetailsController {
#Autowired
private UsersService usersService;
#CrossOrigin(origins = "http://localhost:4200")
#PreAuthorize("hasAuthority('SUPER_ADMIN')" + "or hasAuthority('USER') and authentication.getName().equals(#username)")
#GetMapping(path = "/user/{username}")
public ResponseEntity<?> getUserDetailByUsername(#PathVariable("username") String username, Authentication authentication) {
return ResponseEntity.ok(usersService.getUserByUsername(username));
}
}
spEL references document: Spring Expression Language
, Enable #PreAuthorize reference: Introduction to Spring Method Security

How to fix Cors error Access-Control-Allow-Origin missing

I have a spring boot rest application and I am not using Spring security. My rest service looks like this
#RestController
#CrossOrigin
public class AuthenticationService {
...
#GetMapping(path = "/getUser")
public JSONObject getUser() {
...
}
}
I call the API from a REST application using axios get. Everything works fine locally.
But when the application is deployed on cloud as a docker image, I get the 403 error
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Even when I add a CorsConfiguration file I get the same error.
#Configuration
public class CorsConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedHeaders("Accept", "Origin", "X-Requested-With,Content-Type", "Authorization", "X-XSRF-Header")
.allowCredentials(true);
}
};
}
}
I have spent a lot of time to find a solution for this but somehow it isn't working.
Declaring a bean works fine for me:
#Configuration
public class WebConfigurer implements ServletContextInitializer, WebMvcConfigurer {
private final Environment env;
private final MyProperties properties;
public WebConfigurer(Environment env, MyProperties properties) {
this.env = env;
this.properties = properties;
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = properties.getCors();
if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
log.debug("Registering CORS filter");
source.registerCorsConfiguration("/api/**", config);
source.registerCorsConfiguration("/management/**", config);
source.registerCorsConfiguration("/v3/api-docs", config);
}
return new CorsFilter(source);
}
}
Yaml properties:
# CORS is only enabled by default with the "dev" profile
cors:
allowed-origins: '*'
allowed-methods: '*'
allowed-headers: '*'
exposed-headers: 'Authorization,Link,X-Total-Count'
allow-credentials: true
max-age: 1800
fixed by adding spring security

JAXB class returned from #RestController XML elements wonky

I am porting an old application that runs on JBoss to Spring Boot/Tomcat and have most everything working except the response XML. The old code appears to be using xmlbeans for the XSD source generation. I've changed this to use JAXB. Here's my class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "EventsResponseType1_1", propOrder = {
"getAllEventCodesResponse",
"saveEventCodeResponse",
"failMessageResponse",
"getEmailHistoryResponse"
})
public class EventsResponseType11 {
protected GetAllEventCodesResponseType getAllEventCodesResponse;
protected SaveEventCodeResponseType saveEventCodeResponse;
#XmlElement(name = "FailMessageResponse")
protected ResponseType failMessageResponse;
protected GetEmailHistoryResponseType getEmailHistoryResponse;
// Getters and setters
}
And one of the element classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "getAllEventCodesResponseType", propOrder = {
"_return",
"results"
})
public class GetAllEventCodesResponseType {
#XmlElement(name = "Return", required = true)
protected ReturnType _return;
#XmlElement(name = "Results")
protected GetAllEventCodesResponseType.Results results;
// Getters and setters
}
Here's the response XML:
<com.foo.bar.EventsResponseType11>
<getAllEventCodesResponse>
<__return>
<returnCode>0</returnCode>
<returnMessage />
</__return>
<results>
<eventCodes>
<com.foo.bar.EventCodeInfoType>
<eventCodeID>1</eventCodeID>
<eventCode>1000</eventCode>
<eventCodeDesc>Success</eventCodeDesc>
<eventCodeIndicator>SUCCESS</eventCodeIndicator>
<eventCodeContext>General</eventCodeContext>
<createdBy>system</createdBy>
</com.foo.bar.EventCodeInfoType>
</eventCodes>
</results>
</getAllEventCodesResponse>
</com.foo.bar.EventsResponseType11>
I have configured my application:
#SpringBootApplication
#ComponentScan("com.foo.bar")
public class WsApp extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(WsApp.class, args);
}
/**
* Configure the XML as the only return type on requests
*/
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_XML);
XStreamMarshaller xmlMarshaller = new XStreamMarshaller();
MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(xmlMarshaller);
xmlConverter.setSupportedMediaTypes(mediaTypes);
converters.add(xmlConverter);
super.configureMessageConverters(converters);
}
}
And my controller:
#RestController
#RequestMapping("/go")
public class EventService {
#RequestMapping(value = "/events", method = RequestMethod.POST)
public ResponseEntity<EventsResponseType11> events(#RequestBody EventsRequestType11 request){
EventsResponseType11 responseDoc = eventCodesProxy.invoke(request);
return ResponseEntity.ok(responseDoc);
}
}
So my first question is, how can I stop the marshaller from including the package name on those elements that have it.
And second, since the XSD defines a field as "return" JAXB added an underscore to the field name. The #XmlElement annotation on that field identifies this as "Return" which is what I want on the response (without any underscores)
I've tried using a JAXB Marshaller in place of the XStreamMarshaller with no luck. If at all possible, I would opt not to modify the schema because it's old and has a lot of inter-department dependencies.
Thanks in advance for your help!
So after a lot of trial and error, I stumbled upon this post:
Spring 4 mvc REST XML and JSON response
My application class:
#SpringBootApplication
#ComponentScan("com.foo.bar")
#EnableWebMvc
public class WsApp extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(WsApp.class, args);
}
/**
* Configure the negotiator to return ONLY XML
*/
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_XML).
mediaType("xml", MediaType.APPLICATION_XML);
}
}
I stated before that I wouldn't be too happy about modifying the XSDs, but I had to make a few tweaks to add the #XmlRootElement. I had tried to modify the JAXB source generation through additional libraries but that didn't work out so well.

Register a CustomConverter in a MongoTemplate with Spring Boot

How can I register a custom converter in my MongoTemplate with Spring Boot? I would like to do this only using annotations if possible.
I just register the bean:
#Bean
public MongoCustomConversions mongoCustomConversions() {
List list = new ArrayList<>();
list.add(myNewConverter());
return new MongoCustomConversions(list);
}
Here is a place in source code where I find it
If you only want to override the custom converters portion of the Spring Boot configuration, you only need to create a configuration class that provides a #Bean for the custom converters. This is handy if you don't want to override all of the other Mongo settings (URI, database name, host, port, etc.) that Spring Boot has wired in for you from your application.properties file.
#Configuration
public class MongoConfig
{
#Bean
public CustomConversions customConversions()
{
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
converterList.add(new MyCustomWriterConverter());
return new CustomConversions(converterList);
}
}
This will also only work if you've enabled AutoConfiguration and excluded the DataSourceAutoConfig:
#SpringBootApplication(scanBasePackages = {"com.mypackage"})
#EnableMongoRepositories(basePackages = {"com.mypackage.repository"})
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication
{
public static void main(String[] args)
{
SpringApplication.run(MyApplication.class, args);
}
}
In this case, I'm setting a URI in the application.properties file and using Spring data repositories:
#mongodb settings
spring.data.mongodb.uri=mongodb://localhost:27017/mydatabase
spring.data.mongodb.repositories.enabled=true
You need to create a configuration class for converter config.
#Configuration
#EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
#Profile("!testing")
public class MongoConfig extends AbstractMongoConfiguration {
#Value("${spring.data.mongodb.host}") //if it is stored in application.yml, else hard code it here
private String host;
#Value("${spring.data.mongodb.port}")
private Integer port;
#Override
protected String getDatabaseName() {
return "test";
}
#Bean
public Mongo mongo() throws Exception {
return new MongoClient(host, port);
}
#Override
public String getMappingBasePackage() {
return "com.base.package";
}
#Override
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new LongToDateTimeConverter());
return new CustomConversions(converters);
}
}
#ReadingConverter
static class LongToDateTimeConverter implements Converter<Long, Date> {
#Override
public Date convert(Long source) {
if (source == null) {
return null;
}
return new Date(source);
}
}

Resources