I have a Spring Boot application that is pushed on Bluemix as a CF app.
It works efficiently with the http protocol. However if i tried to force https, I get a 502 error.
I have:
#Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().anyRequest().requiresSecure();
//http.csrf().disable();
}
}
And I have an application.properties file with those entries:
server.ssl.key-store = classpath:**.jks
server.ssl.key-store-password = *******
server.ssl.key-password = ******
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto
I am aware that Bluemix performs SSL termination; in fact it sets correctly x-forwarded-proto and x-forwarded-for. I looked for solutions like 1 and 2 but without any luck.
I then tried with the following solution, as suggested in this article but a received a redirect loop insted:
#Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(){
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
}
What did I miss in my approach? Many thanks for any tips/suggestions you may provide me
For the sake of the community, it would be good to see Rob's comment accepted as the answer. Rob, feel free to add your own answer if you would rather see that accepted instead.
Tomcat is not detecting the x-forwarded headers as being a trusted proxy. Try setting server.tomcat.internal-proxies=.* and logging.level.org.apache.catalina.valves=DEBUG
Related
The developed website works fine on remote server and local machine (when using STS IDE) , recently I started use Intellij IDEA (I created a duplicate of the website code with no any changes ), I started getting the URL was not normalized error.
Does intellij handles Spring security somehow differently than STS ? or what could be the cause?
I don't want use custom httpfirewal .
#EnableGlobalMethodSecurity(prePostEnabled=true)
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider())
.jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// URLs matching for access rights
http.authorizeRequests()
.antMatchers( "/", "/contact","/register").permitAll()
.antMatchers("/accounts").hasAnyAuthority("SUPER_USER","ADMIN_USER")
.anyRequest().authenticated()
.and()
// form login
.csrf().disable().formLogin()
.loginPage("/index")
.failureUrl("/index?error=true")
.defaultSuccessUrl("/user")
.usernameParameter("email")
.passwordParameter("password")
.and()
// logout
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and()
.exceptionHandling()
.accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}
and this is from the properties :
# Spring MVC view prefix.
spring.mvc.view.prefix=/templates/
# Spring MVC view suffix.
spring.mvc.view.suffix=.html
the error is :
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL was not normalized.
P.S: I'm using JDK8 ,Spring Boot 2,Spring Security ,thymeleaf,intellij U 2019.2
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL was not normalized.
Which IDE to use should not have any differences for running the same source codes on the embeddable server configured by springboot. This error happens when the HTTP requests that send to server is not normalised which the URL contains character sequences like ./, /../ , // or /. So I doubt that it is due to you are using different URL to browse the app. For example, you are accidentally adding a '/' in the URL such as http://127.0.0.1:8080/app//index.html
You can change to use a less secure HttpFirewall to avoid such checking by :
#Override
public void configure(WebSecurity web) throws Exception {
web.httpFirewall(new DefaultHttpFirewall());
//another configuration .....
}
P.S. Though it is called DefaultHttpFirewall , it is not the default HttpFirewall used by Spring Security since 4.2.4 which is less secured than the actual default StrictHttpFirewall
To create end-to-end local tests of data workflow I utilize "mock S3" container (e.g adobe/S3Mock). Seems to work just fine. However, some parts of the system rely on S3A client. As far as I see, its format does not allow to point to particular nameserver or endpoint.
Is it possible to make S3A work in local environment?
you talking about the ASF Hadoop S3A Connector? Nobody has tested against S3 mock AFAIK (never seen it before!), but it does work with non-AWS endpoints
set fs.s3a.endpoint to the URL of your S3 connection. There's some settings about switching from https to http (fs.s3a.connection.ssl.enabled = false) and moving from virtual hosts to directories (fs.s3a.path.style.access = true) which will also be needed.
further reading
Like I said: nobody has done this. We developers just go against the main AWS endpoints with its problems (latency, inconsistency, error reporting, etc), precisely because its what you get in production. But for your local testing, it will simplify your life (and you can run it under jenkins without having to give it any secrets)
Answer by #stevel worked for me. Here is the code if someone wants to refer
class S3WriterTest {
private static S3Mock api;
private static AmazonS3 mockS3client;
#BeforeAll
public static void setUp() {
//start mock s3 service using findify
api = new S3Mock.Builder().withPort(8001).withInMemoryBackend().build();
api.start();
/* AWS S3 client setup.
* withPathStyleAccessEnabled(true) trick is required to overcome S3 default
* DNS-based bucket access scheme
* resulting in attempts to connect to addresses like "bucketname.localhost"
* which requires specific DNS setup.
*/
EndpointConfiguration endpoint = new EndpointConfiguration("http://localhost:8001", "us-west-2");
mockS3client = AmazonS3ClientBuilder
.standard()
.withEndpointConfiguration(endpoint)
.withPathStyleAccessEnabled(true)
.withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()))
.build();
mockS3client.createBucket("test-bucket");
}
#AfterAll
public static void tearDown() {
api.shutdown();
}
#Test
void unitTestForHadoopCodeWritingUsingS3A {
Configuration hadoopConfig = getTestConfiguration();
........
}
private static Configuration getTestConfiguration() {
Configuration config = new Configuration();
config.set("fs.s3a.endpoint", "http://127.0.0.1:8001");
config.set("fs.s3a.connection.ssl.enabled", "false");
config.set("fs.s3a.path.style.access", "true");
config.set("fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider");
config.set("fs.s3a.access.key", "foo");
config.set("fs.s3a.secret.key", "bar");
return config;
}
}
I have put in the password which is "root" and it keeps popping back up. How can I suppress this or get rid of it. I am using spring boot and spring security.
application.properties
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootpractice
spring.datasource.username=root
spring.jpa.database = MYSQL
spring.jpa.show-sql = true
# Hibernate
hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql: true
hibernate.hbm2ddl.auto: update
entitymanager.packagesToScan: /
I am using intellij 14 if that matters.
----Update 1-----
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
This class has to be in a parent package of all other packages:
WebSecurityConfig.
Also in application.properties set:
security.basic.enabled=false
ACV's answer is probably the easiest way to turn off the authentication completely by adding security.basic.enabled=false to the application.properties file which is usually located under src/main/resources folder.
or you just type in the password :)
1. use default password
When you run your spring application, there is usually a whole bunch of logging printed, which people usually don't read. The password is actually generated and printed to the screen at the startup. and the username is simply user. If you are testing using a browser and it probably only need you enter it once and caches it, so once for all, you should be securely logged in without authenticating every time.
(however, every time you restart your app, it will generate a new password)
2. customize your password
Add the following properties to your application.properties if you want to customize your username and password:
security.user.name=myuser
security.user.password=mypassword
And here is how it looks like with your own username and password
Reference:
Spring Boot Features - Security
Monitoring and Management over HTTP
You can bypass this spring boot security mechanism. See an example below for this:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class})
public class SampleSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SampleSpringBootApplication.class, args);
}
}
When Spring Security is in the classpath, Spring Boot by default secures all your pages with Basic authentication. That's why you are being asked for userid and password.
You will need to configure the security. To do so, commonly people would extend a WebSecurityConfigurerAdapter, like this:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
...
Refer this Spring Security guide for more details.
Here was the issues
(1) .loginPage("/index") was saying my login page was at index, however I just wanted to use spring's default login page.
(2) had to to move the security package inside the demo package (the main package). Thanks to #Sanjay for suggesting that. I tried to use #ComponantScan but it could not get it to work.
I am using apache cxf java client to connect my WS. I am also using NTLM for authentication.
Now problem I am facing due to credential caching. First time i tried user which does not have privileges to access WS method. when I changed the user , it is still using same user to access WS method.
I am running in tomcat, so cannot kill my JVM .. tried all possible combination on httpClientPolicy.
Any help will be appreciated.
This is NTLM specific problem. sun.net.www.protocol.https.HttpsURLConnectionImpl is getting serverAuthorization via java.net.Authenticator. requestPasswordAuthentication(). This authorization info is maintained in sun.net.www.protocol.http.AuthCacheValue.cache.
So if we override sun.net.www.protocol.http.AuthCacheValue means we can fix this issue.
AuthCacheValue.setAuthCache(new AuthCache()
{
#Override
public void remove(String arg0, AuthCacheValue arg1) { }
#Override
public void put(String arg0, AuthCacheValue arg1) { }
#Override
public AuthCacheValue get(String arg0, String arg1)
{
return null;
}
});
Reference :
http://web.archiveorange.com/archive/v/ACbGtycfTs2dqbRNpy6d
http://tigrou.nl/2011/06/11/cached-credentials-in-http-basic-authentication/
I googled and tried a lot of solutions to this problem.. apparently the simplest code that worked is as below using the JCIFS library
//Set the jcifs properties
jcifs.Config.setProperty("jcifs.smb.client.domain", "domainname");
jcifs.Config.setProperty("jcifs.netbios.wins", "xxx.xxx.xxx.xxx");
jcifs.Config.setProperty("jcifs.smb.client.soTimeout", "300000"); // 5 minutes
jcifs.Config.setProperty("jcifs.netbios.cachePolicy", "1200"); // 20 minutes
jcifs.Config.setProperty("jcifs.smb.client.username", "username");
jcifs.Config.setProperty("jcifs.smb.client.password", "password");
//Register the jcifs URL handler to enable NTLM
jcifs.Config.registerSmbURLHandler();
Apparently CXF 3.0 doesnt have a valid way of configuring the HTTP Client (4.3.x) with NTCredentials instance. Please refer to bug https://issues.apache.org/jira/browse/CXF-5671
By the way, if you have a simple message which needs to be transmitted, just use HTTP Client (I worked using 4.3.4.. not sure of the earlier versions) with NTCredentials Instance. That too did the magic for me.. The sample is as below:
final NTCredentials ntCredentials = new NTCredentials("username", "Passworrd","destination", "domain");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, ntCredentials);
CloseableHttpClient httpclient = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.build();
We're using EJB3 on GlassFish v2.
My application includes a GenericServlet called StartupServlet, which has an init method. java.util.TimerTask pollers started from this method cannot lookup facades from the InitialContext.
However if I make an HTTP request and do a lookup, it succeeds. Therefore I have a workaround now where my poller startup code makes an HTTP connection to a page which looks up the interfaces they need.
How can I rearrange my application so I don't need to use such a hack? If possible the solution needs to work on GFv3 as well.
Thanks in advance for your help!
On GF 2, I have a servlet that on start ensures that my timer is created. This looks up a remote session bean and calls it successfully from the init() (not actual code, distilled down to the important parts):
#EJB(name="TimerSessionRef", beanInterface=TimerSessionRemote.class)
public class StartTimers extends HttpServlet {
#Override
public void init() throws ServletException {
super.init();
try {
Context ctx = new InitialContext();
TimerSessionRemote timerSession = (TimerSessionRemote) ctx.lookup("java:comp/env/TimerSessionRef");
timerSession.createTimer();
} catch (NamingException ex) {
logger.blah();
}