There is a Spring Security configuration in my application, so all the rest interfaces need to pass some filters and authentication.
This is the security configuration I have:
#Configuration
#EnableWebSecurity
public class MyProgramSecurityConfiguration extends WebSecurityConfigurerAdapter {
....
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.addFilterBefore(restBasedAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.logout().permitAll(false)
.addLogoutHandler(logoutHandler).logoutRequestMatcher(new AntPathRequestMatcher(LOGIN_PATH, HttpMethod.DELETE.toString()))
.logoutSuccessHandler(getLogoutSuccessHandler())
.and()
.sessionManagement().maximumSessions(5);
http.addFilterAfter(termsAndConditionsFilter, TermAndConditionFilter.class);
http.addFilterAfter(certificateValidationFilter, TermsAndConditionsFilter.class);
... // some other filters
}
....
}
But, as I described in the title of the question, I would like to have one endpoint /internal/application/info that can be called by anyone without any need of authentication, logging or whatever. I think that you can do it with regexMatcher, am I right?
I think you should to add one more method of HttpSecurity class, something like that:
....
.and()
.authorizeRequests()
.antMatchers("/internal/application/info")
.permitAll()
....
Related
I have a rest api using apache camel. When I hit a post request on a route, it should get a file from S3. I am sending json data(filename, bucketName, accesskey, secretkey, region) in order to extract the file from s3. Here is the code for that ->
public static class HelloRoute extends RouteBuilder {
#Override
public void configure() {
rest("/")
.post("file-from-s3")
.route()
.setHeader(AWS2S3Constants.KEY, constant("filename"))
.to("aws2-s3://bucketnameaccessKey=INSERT&secretKey=INSERT®ion=INSERT&operation=getObject")
.to("file:/tmp/")
The issue is that I don't want the .setHeader(AWS2S3Constants.KEY, constant("filename"))
part. Is there a way to remove that and put an alternate to that in the URI itself. I tried something like this ->
public static class HelloRoute extends RouteBuilder {
#Override
public void configure() {
rest("/")
.post("file-from-s3")
.route()
.to("aws2-s3://bucketnameaccessKey=INSERT&secretKey=INSERT®ion=INSERT&filename=hello.txt&operation=getObject")
.to("file:/tmp/")
But this is giving me an error java.lang.IllegalArgumentException: AWS S3 Key header missing.. Is there some other way to do this?
Sometimes build an AWS Request can be complex, because of multiple options. We introduce the possibility to use a POJO as body.
Take a look at: https://camel.apache.org/components/latest/aws2-s3-component.html#_using_a_pojo_as_body
i am using PowerMockRunner in a spring-boot application for testing. Everything is working but when my controllers actions definition contain someControllerMethod(..., Authentication auth, ...). Then auth is null and therefore some code is not working.
What i tried is to mock Authentication and SecurityContext. Came up with something like this
private void mockSecurity() {
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
List<SimpleGrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("USER"));
User mockedUser = new User("testuser", "passwordtest", authorities);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockedUser);
when(SecurityContextHolder.getContext().getAuthentication().getName()).thenReturn(mockedUser.getUsername());
}
Now those mocks work, if my code uses SecurityContextHolder.getContext().getAuthentication() method of accessing the authentication, but not for the one automatically injected (probably because it is not yet mocked when the controller mock is created).
Any ideas how to mock the injected Authentication so the code does not need to be changed? spring-security-testand #MockWithUser have the same result.
Relevant parts of the test look like this,
#RunWith(PowerMockRunner.class)
public class UserControllerTest {
#InjectMocks
UserController userController;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = standaloneSetup(userController).build();
}
#Test
public void getUserDetails() {
mockSecurity();
mockMvc.perform(...).andExpect(...);
}
}
Edit as requested by pvpkiran the controller code
#RequestMapping(...)
public void getDetails(#PathVariable String id, Authentication auth) {
UserDetails loadedDetails = userService.getUserDetails(id);
if (!loadedDetails.getUserId().equals(auth.getName())) {
throw new Exception(...);
}
...
}
I'm currently trying to write an integration test for some controller whereby it is necessary to send an authentication header. In my controller I have some actions made public accessible through the following code:
namespace App\Controller\Api;
use Cake\Event\Event;
use Cake\Network\Exception\UnauthorizedException;
use Cake\Utility\Security;
use Firebase\JWT\JWT;
class UsersController extends AppController
{
public function initialize()
{
parent::initialize();
$this->Auth->allow(['add', 'token']); // public methods
}
.....
}
Now I have an integration test case in which I want to allow that all actions are possible to access without authentication. Is there any simple way to make this possible?
Integration case code:
namespace App\Test\TestCase\Controller;
use App\Controller\Api\UsersController;
use Cake\TestSuite\IntegrationTestCase;
class ApiPicturesControllerTest extends IntegrationTestCase{
public $fixtures = [
'app.albums',
'app.pictures',
'app.users',
'app.comments',
'app.users_albums'
];
public function setUp(){
parent::setUp();
// Allow all actions
// $this->Auth->allow();
}
public function testViewShouldPass(){
$this->configRequest([
'headers' => [
'Accept' => 'application/json'
]
]);
$data = $this->get('/api/pictures/1.json');
$this->assertResponseOk();
}
}
Generally it's possible to manipulate the controller in an overriden \Cake\TestSuite\IntegrationTestCase::controllerSpy() method, like
public function controllerSpy($event)
{
parent::controllerSpy($event);
if (isset($this->_controller)) {
$this->_controller->Auth->allow();
}
}
but as already mentioned in the comments, it would be better to properly authenticate your requests instead!
While integration tests do not necessarily have to be black-box tests, peering into the internals of the test subject isn't an overly good idea. Mocking certain parts in an integration test might be reasonable when you are looking for something in between "test everything" and "test units", ie larger groups of modules, but that should mostly only be necessary when heavy complexity is involved in a request.
See also
API > \Cake\TestSuite\IntegrationTestCase::controllerSpy()
API > \Cake\TestSuite\IntegrationTestCase::$_controller
I am working currently on project where Apache CXF is integrated with Apache Camel. Apache CXF is a solution that we use to expose a WebService then marshal/unmarshal SOAP request and pass it to Camel. This is pretty standard. By default a POJO dataFormat in ApacheCXF is used however there is a need for getting some information form SOAP headers "" and pass it to Camel. My question is how to do this? When I use Interceptor in Apache CXF I can get information that I need but I cannot pass it then to Camel. The class below is a CXF Interceptor
public class MyInterceptor extends AbstractSoapInterceptor {
//..... some variables
#Override
public void handleMessage(SoapMessage message) throws Fault {
//..some logic and then setting a variable
message.getExchange().put("Foo", "Bar");
}
}
... and class below is Camel Processor that is eventually called:
public class MyCamelProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
//how can I read information from CXF Intercptor here?
//how can I read "Foo" value?
}
}
I understand that Exchange class that is used by Apache CXF is different then Exchange used by Camel however there should be a way of passing information between these two integrated technologies?
Finally, I solved it how follow:
In my context, I have a consumer service with camel-cxf component which is routed to Processor.
CxfEndpoint class from Camel has a method call setInInterceptors:
public void setInInterceptors(List<org.apache.cxf.interceptor.Interceptor<? extends org.apache.cxf.message.Message>> interceptors)
Therefore, if we define the next in our beans definitions file:
...
<cxf:cxfEndpoint id="consumerId"
address="/myservice"
serviceClass="com.example.service.MyServiceSEI">
<cxf:inInterceptors>
<ref bean="myInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean id="myInterceptor" class="com.example.interceptors.MyInterceptor" />
Then, in our custom Interceptor we can set any variable in a map
...
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
...
public class MyInterceptor extends AbstractSoapInterceptor {
public MyInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
//..some logic and then setting a variable
message.getExchange().put("Foo", "Bar");
}
}
Finally, we can get the variables in our Processor, using org.apache.cxf.message.Message class, different from org.apache.camel.Message used with Exchange.getIn() method
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.cxf.message.Message;
import org.apache.camel.component.cxf.common.message.CxfConstants;
public class MyCamelProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
//how can I read information from CXF Intercptor here?
//how can I read "Foo" value?
Message cxfMessage = exchange.getIn().getHeader(CxfConstants.CAMEL_CXF_MESSAGE, Message.class);
String foo = (String) cxfMessage.getExchange().get("Foo");
// read message from camel context
org.apache.camel.Message inMessage = exchange.getIn();
...
}
}
Thanks: http://camel.465427.n5.nabble.com/Getting-entire-Soap-Message-with-header-and-body-in-Payload-mode-td5753162.html
i seem to run into a small issue when using #Autowired into a custom cxf interceptor.
My use case is that i want to log soap messages and send these using AMQP to another system. This process works for normal services etc.
But whatever i do, the needed properties do not get autowired and stay null.
I checked the Spring DI log and the context is scanned and pickedup, so what am i missing?
Is this even possible in CXF interceptors?
#Component
public class LogInInterceptor extends AbstractSoapInterceptor {
private #Value("#{rabbitMQProperties['rabbitmq.binding.log.soap']}")
String binding;
#Autowired
AmqpTemplate amqpTemplate;
public LogInInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
logIt(soapMessage);
}
private void logIt(SoapMessage message) throws Fault {
// rest of the code omitted...!!!
amqpTemplate.convertAndSend(binding, buffer.toString());
}
}
You can't mix #InInterceptors (a CXF annotation) and #Component (a Spring annotation). That will create two separate instances of your interceptor: the one whose dependencies are getting injected by Spring, and one created by CXF. (You are providing class names in the #InInterceptors annotation, not a bean ID, so CXF has no way of knowing that you already created an instance in the Spring context.)
Remove the #InInterceptors annotation and, in addition to the component scan:
<context:component-scan base-package="org.example.config"/>
You also need something like this in your application context:
<jaxws:endpoint id="myWebService" address="/MyWebService">
<jaxws:inInterceptors>
<ref bean="myInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
I know this is an old question, but Jonathan W's answer helped me and I would like to add to it.
This is how I got custom interceptors and #Autowired to work with Spring Boot 1.3.1:
http://cxf.apache.org/docs/jax-ws-configuration.html
import java.util.Arrays;
import javax.jws.WebService;
import org.apache.cxf.Bus;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
#Configuration
#EnableAutoConfiguration
#ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class Application extends SpringBootServletInitializer {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private MyInterceptor myInterceptor;
#Autowired
private HelloWorldImpl helloWorldImpl;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// Replaces the need for web.xml
#Bean
public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
return new ServletRegistrationBean(new CXFServlet(), "/api/*");
}
// Replaces cxf-servlet.xml
#Bean
// <jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
public EndpointImpl helloService() {
Bus bus = (Bus) applicationContext.getBean(Bus.DEFAULT_BUS_ID);
EndpointImpl endpoint = new EndpointImpl(bus, helloWorldImpl);
// Set interceptors here
endpoint.setInInterceptors(Arrays.asList(myInterceptor));
endpoint.publish("/hello");
return endpoint;
}
// Used when deploying to a standalone servlet container, i.e. tomcat
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
// Web service endpoint
#WebService(endpointInterface = "demo.spring.service.HelloWorld")
//#InInterceptors not defined here
public static class HelloWorldImpl {
}
public static class MyInterceptor extends LoggingInInterceptor {
// #Autowired works here
}
}