I have a web application with separate front and back:
/project
+--- /back
+--- /front
The back is developped using Spring boot + Spring MVC, while the front is using AngularJS.
I am trying to set up the security for the communication between the back/front. What I did:
- create a ConfigSecurity class which extends from WebSecurityConfigurerAdapter
- create a SpringWebMvcInitializer which extends from AbstractAnnotationConfigDispatcherServletInitializer and call ConfigSecurity
- create a SecurityWebInitializer class which extends AbstractSecurityWebApplicationInitializer
My ConfigSecurity looks like this:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ConfigSecurity extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/demo/**","/home").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin().loginPage("...")
.and()
.httpBasic();
}
}
My problems:
In configureGlobal(), I can set the username and password to access my protected urls, but how can I do when there is not only one single user? I mean, I want to grant access to all the users that are registered in my database.
Since the back and the front are only communicating with REST (through JSON files), what should be done with formLogin() in ConfigSecurity? By default, Spring Security generates a default login form. I don't need a it in the back of the application since it is the front which is responsible for displaying the loginPage. How can I skip the login page in the back? Maybe by putting the username and password in JSON file the front is sending to the back? Does someone know how it can be done?
I am using Java Configuration for Spring (not XML configuration).
You have many options, all of them require quite a lot of code, but most of it is already well implemented around the internet so you just would have to make it fit your needs. You can either go with simplest way which would be http sessions, JSON token or JWT (JSON web token) or anything else.
Spring blog has a very long post about how to implement different
solutions here:
https://spring.io/guides/tutorials/spring-security-and-angular-js/
JHipster also has different authentication methods which you can take a look at. They have very well implemented role security in front-end which I like a lot and would really suggest looking into: https://github.com/jhipster/jhipster-sample-app
Here's also a JWT which is requires the most code: http://blog.jdriven.com/2014/10/stateless-spring-security-part-2-stateless-authentication/
HTTP Sessions would definitely be the easiest to set up and is well supported by Spring Security out of the box already.
Found great help on this baeldung website (even though it is using XML configuration) and this website (using Java configuration).
For global explanation of how Spring security works, this link helps me a lot.
Related
I have an application written with Spring Boot and AngularJS. When I try to hit a REST service as part of this application, I am able to hit it with POST method wherever POST is configured for request mapping.
But if I try to request AngularJS bind pages, I get a "405 method not supported" exception. So I try to create HTML and JSP pages too, which are not bound to Angular but still, I am getting the same exception.
Where can I start debugging this, and what is the likely reason?
i am sharing here furthere details about issue.
Basically this existing application created/developed with Jhipster, angularjs, Spring boot and spring security does not allow to access html/angularjs related resources with POST from outside. I will explain here what different scenarios work and what is not not working. 1.Postman trying to access base url trying to fetch index.html from same application- Give 405 Post method not allowed.2.Created an independent Test.html in same application and trying to access it from postman- Gives 405 Post method not allowed.3.Created a service which allows POST access in same application- Able to hit service from WSO2 IS IDP and also from Postman.4.Created a separate application on tomcat and provided as callback in WSO2 IDP with starting point for SSO from base url of existing application- Able to hit callback URL on tomcat server. Firefox shows that a POST request was generated for callback URL from WSO2 IS IDP to tomcat based application 5.Created a separate application with Angular js and Spring boot and provided as callback in WSO2 IDP with starting point for SSO from base url of existing application- Able to hit callback URL on tomcat server. Firefox shows that a POST request was generated for callback URL from WSO2 IS IDP to new application with Spring boot and Angularjs. This took me down to conclusion that one of three is causing this issue
1. Spring security generated from JHipster
2. Angularjs
3. Some CORS or other filter from Spring Security is causing this issue.
Till now we have tried to different debugging methods like
1. disable CORS,
2. in angularjs-resource.js enable POST for get operation,
3. In SecurityCOnfigurer, try to permit POST method for base URL or resolve it to GET in httpsercurity authorizerequest etc.
4. Also ignoring resources in websecurity.
Application stack for existing application which we are trying to implement SSO is as below
1. Angularjs 1.5.8
2. Springboot 1.5.9.release
3. WSO2IS 5.4.1
4. WSO2AM 2.1.0
5. JHipster
Let me know if any particular area which we might have missed to analyze or different methods to try.
Thanks,
Sandeep
Try to disable CSRF in security config
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
...
}
...
}
#SpringBootApplication
#Import({
...
SecurityConfig.class
...
})
public class SpringBootApp {
...
}
I have created REST API with Spring Boot and Single Page Application powered by AngularJS.
The question is how to prevent everyone from using my REST api which is available publicly in the internet? I want it to be allowed for usage only from my webpage.
I can not use any secret/password/token from angular side as it would be visible to anyone.
Spring security can help with that. You can define some urls accessible by only certain users having certain roles.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configures(HttpSecurity http) throws Exception {
http.exceptionHandling()
.accessDeniedPage("/error").and()
.authorizeRequests()
.antMatchers("/api/**").hasAnyRole("USER_ROLE");
}
}
So that, only those with role "USER_ROLE" can access any url starts with "/api".
In order to have this functionality, you have to implement a login system which assign the "USER_ROLE" to the users after successful login.
On AngularJs part, it is quite easy. You just make a http request to the REST api, since the browser holds cookies and JSESSIONID, it will be sent along with the request in the header. Spring picks it up and checks if the user having that JSESSIONID has authority to access the url.
I created a web service client to handle cxf soap web services with apache camel.
String serviceUri = "cxf:http://localhost:10000/myservice?serviceClass=" +
MyRequest.class.getCanonicalName();
from(uri).to("mock:xyz");
The web service receives the soap call but throws an exception since the request requires a handling for wss.
org.apache.cxf.binding.soap.SoapFault: MustUnderstand headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood.
The reason is, that the service requires ws security, which can be seen by lloking at the request.
<SOAP-ENV:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
I found out that I need to implement an interceptor to handle header properties.
My questions:
How can I add an interceptor to handle the header attributes with Camel Java-DSL?
Will this be sufficient to get rid of the SOAP Fault?
You can do it through
cxfEndpointConfigurer option #see: Camel-CXF configuration
(I use Spring (it is much easier)), but I guess for DSL URI will look like:
String serviceUri = "cxf:http://localhost:10000/myservice?serviceClass=" +
MyRequest.class.getCanonicalName() +
"&cxfEndpointConfigurer="+ MyConfigurer.class.getCanonicalName();
by implementing org.apache.camel.component.cxf.CxfEndpointConfigurer you have ability to add an Interceptor inside configureServer method
server.getEndpoint().getInInterceptors().add(new MyJAASLoginInterceptor());
if you run your Camel in container with JAAS (like JBOSS) you can use extension from
org.apache.cxf.interceptor.security.JAASLoginInterceptor
with needed callback handler.
Simple example which validates user/password from WSS header against JBOSS users:
public class MyJAASLoginInterceptor extends javax.security.auth.callback.JAASLoginInterceptor {
#Override
protected CallbackHandler getCallbackHandler(String name, String password) {
return new org.apache.cxf.interceptor.security.NamePasswordCallbackHandler(name, password, "setCredential");
}
}
I have a Spring MVC Server Backend with Rest-Services and an AngularJS WebFrontend.
i want to secure my spring mvc rest services but i want use java config.. and i have no idea how the configuration mus look like. Can someone help me with this ?
The only good implementation i have found is this : https://github.com/philipsorst/angular-rest-springsecurity
I use a postgrsDB and i wand store username and password and roles there, is the session token in the example from https://github.com/philipsorst/angular-rest-springsecurity only stored in cache and not in the db ?
At the moment i have a simple form login security, this was only for testing, but i did not use jsp i use only the spring mvc rest services and angularjs as webfrontend.. How can i modify my spring security code that it works with oauth2 like in the example from https://github.com/philipsorst/angular-rest-springsecurity ? I have at the moment only this two classes from spring security..
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("username").password("test").roles("User");
}
}
and then i register the securityConfig in my WebInitializer.
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{ PersistenceContext.class,AppConfig.class,SecurityConfig.class };
} ....
But the roles and username/password should stored in a database.. must i use a special databse schema for spring security to store username,password and roles in my db ?
And can i implement it so that i can only add the #Secured Annotation(or any other Annotation) over one of my rest services with the role in it ? Like #Secured("UserRole")
Or ist Basic Authentification easier ? can i secure my rest services with basic authentification with rolemanagement !? if so we can use basic authentification..
Best regards
In order to load users you have to create an authentication manager and wire a UserDetailsService into that authentication manager. The following doc link gives a good overview of authentication manager, and the core components associated.
http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#core-services
So, to answer your first question...
But the roles and username/password should stored in a database.. must i use a special
databse schema for spring security to store username,password and roles in my db ?
You can do either. If you want, spring security can handle all the database side for you, you just have to supply a reference to a JDBC datasource which has Spring's schema design.
http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#core-services-jdbc-user-service
and
http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#appendix-schema
-or-
You can utilize your own schema by providing a UserDetailsService implementation of your own that will load from your own database schema. Here's some samples that can get you started with that approach.
<context:component-scan base-package="com.example.security" />
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
<bean id="dao-provider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"
p:userDetailsService-ref="myUserDetailsService"
p:passwordEncoder-ref="sha-pw-encoder"
p:saltSource-ref="my-salt-source" />
<bean id="sha-pw-encoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"
p:encodeHashAsBase64="true" />
<bean id="my-salt-source" class="org.springframework.security.authentication.dao.ReflectionSaltSource"
p:userPropertyToUse="salt" />
<security:authentication-manager>
<security:authentication-provider ref="dao-provider"/>
</security:authentication-manager>
Finally, provide an implementation of the UserDetailsService like so:
#Component("myUserDetailsService")
public class MyUserDetailsServiceImpl implements UserDetailsService {
//Reference to the spring JPA repository for loading users
private final UserRepository userRepository;
#Autowired
public MyUserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
#Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByName(username);
if (user != null) {
return new UserDetails() {
... //create the user details from the user object
}
} else {
String err = String.format("Failed to find username: %s in local database. Trying other auth mechanisms.", username);
throw new UsernameNotFoundException(err);
}
}
}
... for your second question:
And can i implement it so that i can only add the #Secured Annotation(or any other
Annotation) over one of my rest services with the role in it ? Like #Secured("UserRole")
Yes, the above configuration will allow you to use #Secured annotation by configuring the global-method-security.
And finally, yes all of this will still utilize basic authentication by default, but can be reconfigured to use digest authentication if necessary. I recommend giving a full read to the docs at http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/ in order to really grasp what you're trying to do. But, this should get you on your way.
I am developing a website using jsp-servlet in google app engine. I want to secure some web pages from all the users that visit my site. So is there any way to password protect my web pages. I know it is easily done by htaccess in apache. Can htaccess work in google app engine? if Yes, please specify the process.
You can take advantage of the App Engine Users API. This allows users to log in to your app using their Google account. If you want to control who can get into what parts of your app, you could check the logged-in user's ID against a list of allowed users in your data store when they make a request to your servlet.
Edit:
You're not going to find a method exactly like using .htaccess files -- that's just not how App Engine works. You have code in your servlets that are responsible for rendering pages. In this code, you'll need to add a check to see if the user has access, but only for the pages that you'd like to check.
Here's a code sample, which I hope might clarify things. This is a slightly-modified version of the code at the link I sent you.
public class MySecretServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
UserService userService = UserServiceFactory.getUserService();
resp.setContentType("text/html");
if (req.getPathInfo().equals("/secret_page") {
if (req.getUserPrincipal() != null &&
req.getUserPrincipal().getUserId().equals("admin-id")) {
// render your protected page here
} else {
resp.getWriter().println("<p>Please <a href=\"" +
userService.createLoginURL(thisURL) +
"\">sign in</a>.</p>");
}
} else {
// render your unprotected content here
}
}
}
Alternatively, you can use the security constraint features in your web.xml file. You can find the documentation for those here. This is less flexible, though, as you can only change access rights between "everyone" and "admin-only".