JerseyTest over HTTPS - java

I'm trying to test a Jersey filter with the Jersey Test Framework and I need it to be done over HTTPS.
I know how to configure the ssl context on the Client but I can't seem to find info on how to run the Grizzly server over HTTPS.
The test:
#Test
public void testPeerTokenOK() {
SSLContext sslContext = getSslContext();
Client client = ClientBuilder.newBuilder().hostnameVerifier((s, session) -> true).sslContext(sslContext).build();
WebTarget target = target().path(URI);
Response response = client.target(target.getUri())
.request(MediaType.APPLICATION_JSON)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON + "; charset=" + StandardCharsets.UTF_8.name())
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
The resource:
#Path(URI)
public static class TestResource {
#GET
#Singleton
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response get(EntityPayLoad payload) throws Exception {
if (payload != null && payload instanceof EntityPayLoad) {
return Response.ok(payload).build();
} else {
return Response.status(Status.BAD_REQUEST.getStatusCode()).build();
}
}
}
The constructor:
#Override
protected Application configure() {
ResourceConfig rc = new ResourceConfig();
rc.register(SpringLifecycleListener.class);
rc.register(RequestContextFilter.class);
rc.register(new JacksonFeature());
rc.register(new ObjectMapperContextResolver());
rc.registerClasses(TestResource.class);
rc.register(AccessTokenFilter.class);
rc.register(PeerTokenFilter.class);
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("filterContext.xml");
rc.property("contextConfig", applicationContext);
return rc;
}
The relevant maven dependency:
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.25</version>
<scope>test</scope>
</dependency>

This question was also asked and answered here: Configure JettyTestContainer with SSL for JerseyTest From version 2.33 onwards it is possible to configure the JerseyTest with your custom ssl configuration. See here for an example:
public class SecuredJerseyTest extends JerseyTest {
#Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyTestContainerFactory();
}
#Path("hello")
public static class TestResource {
#GET
public String hello() {
return "hello";
}
}
#Override
protected Application configure() {
return new ResourceConfig(TestResource.class);
}
#Override
protected URI getBaseUri() {
return UriBuilder
.fromUri("https://localhost")
.port(getPort())
.build();
}
#Override
protected Optional<SSLContext> getSslContext() {
SSLContext sslContext = ... // your initialised server sslContext
return Optional.of(sslContext);
}
#Override
protected Optional<SSLParameters> getSslParameters() {
serverSslParameters = new SSLParameters();
serverSslParameters.setNeedClientAuth(false);
return Optional.of(serverSslParameters);
}
#Test
public void testHello() {
SSLContext sslContext = ... // your initialised client sslContext
Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.build();
WebTarget target = client.target(getBaseUri()).path("hello");
String s = target.request().get(String.class);
Assert.assertEquals("hello", s);
}
}

Related

I am getting swagger ui 403 error how can i fix it?

This is how my microservices classes are. I have two questions.
Firstly, when I run the microservice locally, the swagger document does not open automatically. When I enter the link in the form of host/v2/api-docs with my hand, it opens as json, but the ui part does not come. I can edit and view it with the swagger editor. I added dependency to pom.xml for the UI part, but it doesn't work, how to open the UI screen?
Secondly,
Except for host/v2/api-docs, when I type a link to a controller specifically, I get a 403 authorization error. This is the most important problem that I want to overcome, how can I do it? can you help me?
link/swagger-ui.html#!/signin
localhost:8000/swagger-ui.html#!/signin
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Jun 23 16:04:09 TRT 2022
There was an unexpected error (type=Forbidden, status=403).
Access Denied
My pom.xml is :
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
My SwaggerConfig class is:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any()).build().apiInfo(metaData());
}
#Bean
public UiConfiguration uiConfiguration() {
return UiConfigurationBuilder.builder().deepLinking(true).validatorUrl(null).build();
}
private static final Contact DEFAULT_CONTACT = new Contact("Rosaline Fox,Anna Hurt", "http://www.google.com",
"rosaline.fox#gmail.com,anna.hurt#gmail.com");
private ApiInfo metaData() {
return new ApiInfoBuilder().title("Auth Service Controller API Title")
.description("Auth Service Controller API Description").version("1.0")
.license("Apache License Version 2.0").licenseUrl("https://www.apache.org/licenses/LICENSE-2.0")
.contact(DEFAULT_CONTACT).build();
}
}
My WebSecurityConfig class is:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String XI_PARTNER = "XIPartner";
private static final String XI_CONSULTANT = "XIConsultant";
private static final String SALES = "Sales";
private static final String STANDART = "Standart";
public static final String ADMIN = "Admin";
#Autowired
private JwtTokenProvider jwtTokenProvider;
#Autowired
private FilterChainExceptionHandler filterChainExceptionHandler;
#Autowired
private HandlerExceptionResolver handlerExceptionResolver;
#Override
protected void configure(HttpSecurity http) throws Exception {
// Disable CSRF (cross site request forgery)
http.csrf().disable();
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
// No session will be created or used by spring security
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(filterChainExceptionHandler, LogoutFilter.class);
http.exceptionHandling().accessDeniedHandler((req, res, e) -> handlerExceptionResolver.resolveException(req, res, null, e));
// Entry points
http.authorizeRequests()
.antMatchers("/**/signin/otp", "/**/signin/**", "/**/v2/api-docs/**", "/**/swagger-ui.html#/**").permitAll()
.antMatchers("/**/customers/create").hasAnyAuthority(SALES)
.antMatchers("/**/customers/update").hasAnyAuthority(SALES)
.antMatchers("/**/customers/all").hasAnyAuthority(SALES)
.antMatchers("/**/customers/deactivate").hasAnyAuthority(SALES)
.antMatchers("/**/customers/reactivate").hasAnyAuthority(SALES)
.antMatchers("/**/products/create").hasAnyAuthority(SALES)
.antMatchers("/**/products/update").hasAnyAuthority(SALES)
.antMatchers("/**/users/create").hasAnyAuthority(SALES)
.antMatchers("/**/users/update").hasAnyAuthority(SALES)
.antMatchers("/**/users/deactivate").hasAnyAuthority(SALES)
.antMatchers("/**/users/reactivate").hasAnyAuthority(SALES)
.antMatchers("/**/admin/user/all").hasAnyAuthority(ADMIN)
.antMatchers("/**/xicustomers/create").hasAnyAuthority(SALES)
.antMatchers("/**/xicustomers/update").hasAnyAuthority(SALES)
.antMatchers("/**/xicustomers/all").hasAnyAuthority(SALES)
.antMatchers("/**/partner/create").hasAnyAuthority(SALES)
.antMatchers("/**/xicustomers/list").hasAnyAuthority(XI_PARTNER,XI_CONSULTANT)
.antMatchers("/**/report/list/**").hasAnyAuthority(XI_CONSULTANT)
.antMatchers("/**/originator").hasAnyAuthority(STANDART)
.antMatchers("/**/blackhour/add").hasAnyAuthority(STANDART)
.antMatchers("/**/blackhour").hasAnyAuthority(STANDART)
.antMatchers("/**/access/**").anonymous()
.antMatchers("/**/pwd/forgot").anonymous()
.antMatchers("/**/maximo").anonymous()
.anyRequest().authenticated();
// Apply JWT
http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
// Optional, if you want to test the API from a browser
// http.httpBasic();
}
#Override
public void configure(WebSecurity web) throws Exception {
// Allow eureka client to be accessed without authentication
web.ignoring().antMatchers("/*/")//
.antMatchers("/eureka/**")//
.antMatchers(HttpMethod.OPTIONS, "/**"); // Request type options
// should be
// allowed.
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
}
My Controller Class :
#ApiOperation(value = "Login Service", notes = "Login service with captcha verification.")
#PostMapping("/signin")
#ResponseBody
public ResponseEntity<LoginResponse> login(#RequestBody LoginRequest loginRequest) {
LoginResponse loginResponse = this.loginService.login(loginRequest);
return ResponseEntity.accepted().body(loginResponse);
}
My JwtTokenFilterConfigurer class :
public class JwtTokenFilterConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilterConfigurer(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
#Override
public void configure(HttpSecurity http) throws Exception {
JwtTokenFilter customFilter = new JwtTokenFilter(this.jwtTokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
My JwtTokenFilter class :
#Slf4j
#Component
public class JwtTokenFilter extends GenericFilterBean {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
//HttpServletResponse response = (HttpServletResponse) res;
String requestURI = request.getRequestURI();
String token = getBearerToken((HttpServletRequest) req);
if (token != null && !requestURI.contains("/signin/otp")) {
TokenParams params = null;
try {
params = this.jwtTokenProvider.validateToken(token);
} catch (JwtException | IllegalArgumentException e) {
log.warn("Invalid Token: {}, Error: {}", params, e.getMessage());
//response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "INVALID JWT token");
//return;
throw new UnauthorizedException();
}
if (!params.getRoles().contains(WebSecurityConfig.ADMIN) && params.isForOtp() == true) {
log.warn("Invalid Token: {}, it is for OTP!", params);
//response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "INVALID JWT token");
//return;
throw new UnauthorizedException();
}
Authentication auth = this.jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
HeaderMapRequestWrapper wrappedRequest = new HeaderMapRequestWrapper(request);
wrappedRequest.addHeader("companyId", params.getCompanyId());
wrappedRequest.addHeader("user", params.getEmail());
filterChain.doFilter(wrappedRequest, res);
} else {
filterChain.doFilter(req, res);
}
}
private static final String AUTHORIZATION = "Authorization";
private String getBearerToken(HttpServletRequest req) {
String bearerToken = req.getHeader(AUTHORIZATION);
/*
* if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
* return bearerToken.substring(7, bearerToken.length()); }
*/
if (bearerToken != null) {
return bearerToken;
}
return null;
}
}

Oauth2 refresh with Dagger2 Android

I'm trying to implement Oauth2 login with Dagger2. Once the access_token gets expired, I have successfully generated new access_token through the refresh_token, but the Authenticator goes on infinite loop once refresh_token is also expired.
This is my Network module, where I defined, Authenticator and Interceptor in OkHttp Client
#Module
public class NetworkModule
{
#Provides
#Singleton
OkHttpClient provideOkHttpClient(TokenAuthenticator tokenAuthenticator, TokenInceptor tokenInceptor, SharedManager sharedManager)
{
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// adding socket time for read/write/reconnect
httpClient.connectTimeout(30, TimeUnit.SECONDS);
httpClient.writeTimeout(30, TimeUnit.SECONDS);
httpClient.readTimeout(30, TimeUnit.SECONDS);
// setting the accept type of the request to application/json
httpClient.addNetworkInterceptor(new Interceptor()
{
#Override
public Response intercept(Chain chain) throws IOException {
Request.Builder requestBuilder = chain.request().newBuilder();
requestBuilder.header("Accept", "application/json");
return chain.proceed(requestBuilder.build());
}
});
httpClient.addInterceptor(logging).addInterceptor(tokenInceptor);
httpClient.authenticator(tokenAuthenticator);
return httpClient.build();
}
}
#Provides
Retrofit provideRetrofit(OkHttpClient okHttpClient){
return new Retrofit.Builder()
.baseUrl(ApiConstants.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
}
#Provides
#Singleton
ApiService provideApiService(Retrofit retrofit, TokenService apiServiceHolder)
{
ApiService apiService = retrofit.create(ApiService.class);
apiServiceHolder.setApiService(apiService);
return apiService;
}
#Provides
#Singleton
public SharedPreferences providePreferences(Application application)
{
return application.getSharedPreferences(Constants.APP_PREFERENCES, Context.MODE_PRIVATE);
}
#Provides
#Singleton
public SharedManager provideSharedManager(SharedPreferences sharedPreferences)
{
return new SharedManager(sharedPreferences);
}
#Provides
#Singleton
public TokenAuthenticator tokenAuthenticator(TokenService tokenService, SharedManager sharedManager)
{
return new TokenAuthenticator(tokenService, sharedManager);
}
#Provides
#Singleton
public TokenInceptor tokenInceptor(SharedManager sharedManager)
{
return new TokenInceptor(sharedManager);
}
#Provides
#Singleton
public TokenService apiServiceHolder()
{
return new TokenService();
}
}
Here's the Interceptor
#Singleton
public class TokenInceptor implements Interceptor
{
SharedManager sharedManager;
#Inject
public TokenInceptor(SharedManager sharedManager)
{
this.sharedManager = sharedManager;
}
#Override
public Response intercept(Chain chain) throws IOException
{
Request request = chain.request();
// we don't need header in login/register so, we remove the header from these api request endpoints
if(request.url().encodedPath().contains("/token/client") && request.method().equalsIgnoreCase("POST"))
{
return chain.proceed(request);
}
// then we add the authenticator to other api requests
HttpUrl url = request.url();
Request.Builder urlBuilder = request.newBuilder().addHeader(ApiConstants.AUTHORIZATION, sharedManager.getBearer()).url(url);
Request apiRequest = urlBuilder.build();
return chain.proceed(apiRequest);
}
}
Here's the Authenticator
#Singleton
public class TokenAuthenticator implements Authenticator
{
private SharedManager sharedManager;
private TokenService tokenService;
#Inject
public TokenAuthenticator(#NonNull TokenService apiServiceHolder, SharedManager sharedManager)
{
this.tokenService = apiServiceHolder;
this.sharedManager = sharedManager;
}
#Nullable
#Override
public Request authenticate(Route route, Response response) throws IOException
{
if(!response.request().header(ApiConstants.AUTHORIZATION).equals(sharedManager.getBearer()))
{
return null;
}
retrofit2.Response<TokenResponse> tokenResponse = tokenService.getApiService().refreshToken(sharedManager.getRefresh()).execute();
TokenResponse responseData = tokenResponse.body();
if(tokenResponse.isSuccessful() && responseData!= null)
{
TokenResponse responseRequest = (TokenResponse) tokenResponse.body();
String new_token = responseRequest.getAccess();
sharedManager.saveAccessToken(new_token);
return response.request().newBuilder().header(ApiConstants.AUTHORIZATION,sharedManager.getBearer()).build();
}
else
{
// As per my assumption, the refresh token might expire here
Log.e("refresh_token","expired");
}
return null;
}
}
Here's the TokenService class
public class TokenService
{
ApiService apiService = null;
#Nullable
public ApiService getApiService() {
return apiService;
}
public void setApiService(ApiService apiService) {
this.apiService = apiService;
}
}
Here's SharedManager class
public class SharedManager
{
private SharedPreferences sharedPreferences;
#Inject
public SharedManager(SharedPreferences sharedPreferences)
{this.sharedPreferences = sharedPreferences;};
public void saveAccessToken(String token)
{
sharedPreferences.edit().putString(ApiConstants.ACCESS_TOKEN, token).commit();
}
public void saveRefreshToken(String token)
{
sharedPreferences.edit().putString(ApiConstants.REFRESH, token).commit();
}
public String getAccessToken()
{
return sharedPreferences.getString(ApiConstants.ACCESS_TOKEN, "");
}
public String getRefresh()
{
return sharedPreferences.getString(ApiConstants.REFRESH, "");
}
public String getBearer()
{
return "Bearer "+getAccessToken();
}
public void clearAll()
{
sharedPreferences.edit().clear().commit();
}
}
Here's ApiService interface
public interface ApiService
{
// client login
#POST("token/client")
#FormUrlEncoded
Call<ResponseBody> loginUser(#Field("email") String email,
#Field("password") String password);
// method for refresh token
#POST("token/refresh")
#FormUrlEncoded
Call<TokenResponse> refreshToken(#Field("refresh") String refresh);
// get agent
#GET("agent")
Call<ResponseBody> getAgentTour();
}
Can anyone trace out the faults in the code here ? The code structure changed while posting in stack.
A standard refresh token grant message will return an error code of invalid_grant when the refresh token finally expires.
{
"error": "invalid_grant",
"error_description": "An optional description message that varies between vendors"
}
At this point you should do two things:
For any in flight API calls, throw an exception with an error code such as 'login_required', that your error handling code can silently ignore
Then perform a login redirect to start a new user session
SAMPLE CODE OF MINE
A something to compare against, I have an AppAuth code sample that you can run and which allows simulation of token expiry events:
Android Code to Handle Invalid Grant
Android Code Sample Blog Post
Of course you would need to translate this behaviour to your own Dagger based coding preferences ...

How do you make a secure websocket conneciton with Java on the client side?

There doesn't seem to a clean and simple example of creating a secure websocket connection anywhere on the interwebs, nor instructions to set one up... any ideas?
I would provide some guidelines for websocket authentication. Since websocket is upgraded from http, the authentication is based on http too. You can equip the http connection with ssl or basic or digest auth.
I had worked with spring websocket auth before, ssl is just to upgrade http to https. I would post digest auth for spring websocket here.
1.Configure the server to user digest auth, spring security can get it:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public final static String REALM="MY_REALM";
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN")
.and().withUser("test").password("test").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().authenticationEntryPoint(getDigestEntryPoint())
.and().addFilter(getDigestAuthenticationFilter(getDigestEntryPoint()));
}
#Bean
public MyDigestAuthenticationEntryPoint getDigestEntryPoint() {
MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint = new MyDigestAuthenticationEntryPoint();
digestAuthenticationEntryPoint.setKey("mykey");
digestAuthenticationEntryPoint.setNonceValiditySeconds(120);
digestAuthenticationEntryPoint.setRealmName(REALM);
return digestAuthenticationEntryPoint;
}
public DigestAuthenticationFilter getDigestAuthenticationFilter(
MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint) throws Exception {
DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();
digestAuthenticationFilter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);
digestAuthenticationFilter.setUserDetailsService(userDetailsServiceBean());
return digestAuthenticationFilter;
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
public class MyDigestAuthenticationEntryPoint extends DigestAuthenticationEntryPoint {
#Override
public void afterPropertiesSet() throws Exception{
super.afterPropertiesSet();
setRealmName(WebSecurityConfig.REALM);
}
}
2.Extend from AbstractSecurityWebSocketMessageBrokerConfigurer:
#Configuration
#EnableWebSocketMessageBroker
public class WssBrokerConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpSubscribeDestMatchers("/topic/notification").permitAll()
.simpDestMatchers("/**").authenticated()
.anyMessage().denyAll();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/ws");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hpdm-ws").setAllowedOrigins("*").withSockJS();
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
3.Digest auth for client refer to this post:
spring websocket with digest authentication

How to add a request interceptor to a feign client?

I want every time when I make a request through feign client, to set a specific header with my authenticated user.
This is my filter from which I get the authentication and set it to the spring security context:
#EnableEurekaClient
#SpringBootApplication
#EnableFeignClients
public class PerformanceApplication {
#Bean
public Filter requestDetailsFilter() {
return new RequestDetailsFilter();
}
public static void main(String[] args) {
SpringApplication.run(PerformanceApplication.class, args);
}
private class RequestDetailsFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String userName = ((HttpServletRequest)servletRequest).getHeader("Z-User-Details");
String pass = ((HttpServletRequest)servletRequest).getHeader("X-User-Details");
if (pass != null)
pass = decrypt(pass);
SecurityContext secure = new SecurityContextImpl();
org.springframework.security.core.Authentication token = new UsernamePasswordAuthenticationToken(userName, pass);
secure. setAuthentication(token);
SecurityContextHolder.setContext(secure);
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
private String decrypt(String str) {
try {
Cipher dcipher = new NullCipher();
// Decode base64 to get bytes
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (javax.crypto.BadPaddingException e) {
} catch (IllegalBlockSizeException e) {
} catch (UnsupportedEncodingException e) {
} catch (java.io.IOException e) {
}
return null;
}
}
This is my feign client:
#FeignClient("holiday-client")
public interface EmailClient {
#RequestMapping(value = "/api/email/send", method = RequestMethod.POST)
void sendEmail(#RequestBody Email email);
}
And here I have a request interceptor:
#Component
public class FeignRequestInterceptor implements RequestInterceptor {
private String headerValue;
public FeignRequestInterceptor() {
}
public FeignRequestInterceptor(String username, String password) {
this(username, password, ISO_8859_1);
}
public FeignRequestInterceptor(String username, String password, Charset charset) {
checkNotNull(username, "username");
checkNotNull(password, "password");
this.headerValue = "Basic " + base64encode((username + ":" + password).getBytes(charset));
}
private static String base64encode(byte[] bytes) {
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(bytes);
}
#Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Authorization", headerValue);
}
}
I don't know how to configure this interceptor to my client and how to set the header with the username and password. How can I accomplish that ?
You don't really need your own implementation of the FeignRequestInterceptor as there is already BasicAuthRequestInterceptor in the feign.auth package that does exactly the same.
With this said, you basically have almost everything set up already. All is left to do is to define the basicAuthRequestInterceptor bean with specific username and password:
#Bean
public RequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("username", "password");
}
I know the thread is a bit old but wanted to give some explanation on what's happening here.
If you'd like to customize your Feign requests, you can use a RequestInterceptor. This can be a custom implementation or you can reuse what's available in the Feign library, e.g. BasicAuthRequestInterceptor.
How to register it? Well, there 2 ways to do it depending on how you use Feign.
If you're using plain Feign without Spring, then you gotta set the interceptor to the Feign builder. An example is here.
Feign.builder()
.requestInterceptor(new MyCustomInterceptor())
.target(MyClient.class, "http://localhost:8081");
If you're using Spring Cloud OpenFeign and you use the #FeignClient annotation to construct your clients, then you have to create a bean from your RequestInterceptor by either defining it as a #Component or as a #Bean in one of your #Configuration classes. Example here.
#Component
public class MyCustomInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate template) {
// do something
}
}
Also, you can check out one of my articles in this topic, maybe that clears it up better: Customizing each request with Spring Cloud Feign

Spring-boot jersey : resources not autodiscover

I try to use Spring-boot with jetty and jersey.
No problem with the jetty part. I can start server and spring resources are running (trace, metrics,info,beans,....) but my resources didn't run.
My configuration files are :
Launcher.java
#Configuration
#PropertySource("classpath:application.properties")
#EnableAutoConfiguration
#ComponentScan(basePackages = {"com.fdilogbox.report.serveur"})
public class Launcher extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Launcher.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Launcher.class);
}
#Bean
public ServletRegistrationBean jerseyServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/api/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, ResourcesConfiguration.class.getName());
return registration;
}
#Bean
public EmbeddedServletContainerFactory containerFactory() {
final JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory = new JettyEmbeddedServletContainerFactory() {
#Override
protected JettyEmbeddedServletContainer getJettyEmbeddedServletContainer(Server server) {
return new JettyEmbeddedServletContainer(server);
}
};
jettyEmbeddedServletContainerFactory.addServerCustomizers(new JettyConfiguration());
return jettyEmbeddedServletContainerFactory;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
JettyConfiguration.java
public class JettyConfiguration implements JettyServerCustomizer {
#Override
public void customize(Server server) {
WebAppContext webAppContext = (WebAppContext) server.getHandler();
try {
// Load configuration from resource file (standard Jetty xml configuration) and configure the context.
createConfiguration("/jetty.xml").configure(webAppContext);
createConfiguration("/jetty-rewrite.xml").configure(server);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private XmlConfiguration createConfiguration(String xml) throws IOException, SAXException {
return new XmlConfiguration(Launcher.class.getResourceAsStream(xml));
}
}
ResourcesConfiguration.java
public class ResourcesConfiguration extends ResourceConfig {
public ResourcesConfiguration() {
super();
PackageNamesScanner resourceFinder = new PackageNamesScanner(new String[]{"com.fdilogbox.report.serveur.business.resources"}, true);
registerFinder(resourceFinder);
register(JacksonFeature.class);
}
}
and my resources file :
#Path("builder")
#Component
public class ReportBuilderResource {
#Autowired
private ReportBuilderService reportBuilderService;
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public String[] findAll() {
return reportBuilderService.findAllReport();
}
}
If I try to acces "localhost:9090/api/builder/list" I get an 404 error.
But if I try "localhost:9090/bean" I get all bean on JSon format.
I think I have an error in my conf but I don't know where.
I found my mistake : management port is 9090 but the normal resources port is 8090.

Categories

Resources