I'm new in the Spring's world I'm using Spring Boot 1.2.5 with Spring Security 3.1.2. Due to my project's requirements I need to configure an ACL security model. I have the following java class configuration:
#Configuration
public class ACLConfig {
#Autowired
DataSource dataSource;
#Bean
JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
#Bean
DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
#Bean
EhCacheBasedAclCache aclCache() {
EhCacheFactoryBean factoryBean = new EhCacheFactoryBean();
EhCacheManagerFactoryBean cacheManager = new EhCacheManagerFactoryBean();
cacheManager.setAcceptExisting(true);
cacheManager.setCacheManagerName(CacheManager.getInstance().getName());
cacheManager.afterPropertiesSet();
factoryBean.setName("aclCache");
factoryBean.setCacheManager(cacheManager.getObject());
factoryBean.setMaxBytesLocalHeap("16M");
factoryBean.setMaxEntriesLocalHeap(0L);
factoryBean.afterPropertiesSet();
return new EhCacheBasedAclCache(factoryBean.getObject());
}
#Bean
LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
#Bean
AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"));
}
#Bean
JdbcMutableAclService aclService() {
JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
service.setClassIdentityQuery("select currval(pg_get_serial_sequence('acl_class', 'id'))");
service.setSidIdentityQuery("select currval(pg_get_serial_sequence('acl_sid', 'id'))");
return service;
}
#Bean
AclEntryVoter aclDeleteVoter()
{
AclEntryVoter voter = new AclEntryVoter(aclService(),"ACL_NOMCITY_DELETE", new Permission[] {BasePermission.DELETE});
voter.setProcessDomainObjectClass(NomCity.class);
return voter;
}
#Bean
AclEntryVoter aclUpdateVoter()
{
return new AclEntryVoter(aclService(),"ACL_NOMCITY_UPDATE", new Permission[]{BasePermission.ADMINISTRATION});
}
#Bean
AclEntryVoter aclReadVoter()
{
return new AclEntryVoter(aclService(),"ACL_NOMCITY_READ", new Permission[]{BasePermission.READ});
}
#Bean
AccessDecisionManager accessDecisionManager (){
List<AccessDecisionVoter<? extends Object>> list = new ArrayList<>();
list.add(aclDeleteVoter());
list.add(aclReadVoter());
list.add(aclUpdateVoter());
return new AffirmativeBased(list);
}
}
I have the following RestController's methods, it use the ACLs defined earlier:
#RequestMapping(value = "/nomCitys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#Transactional
#Secured({"ROLE_ADMIN","ROLE_USER"})
public ResponseEntity<NomCity> create(#Valid #RequestBody NomCity nomCity) throws URISyntaxException {
NomCity result = nomCityRepository.save(nomCity);
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
ObjectIdentity oi = new ObjectIdentityImpl(NomCity.class,result.hashCode());
MutableAcl acl = mutableAclService.createAcl(oi);
acl.insertAce(0, BasePermission.ADMINISTRATION, new GrantedAuthoritySid("ROLE_ADMIN"), true);
acl.insertAce(1, BasePermission.DELETE, new PrincipalSid(user.getUsername()), true);
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER"), true);
mutableAclService.updateAcl(acl);
return ResponseEntity.created(new URI("/api/nomCitys/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert("nomCity", result.getId().toString()))
.body(result);
}
When I create a new city the following ACL entries are created too:
The user with ROLE_ADMIN role have Admin permission.
The user how create the city have Delete permission.
The user with ROLE_USER role can read the city.
The following method is the delete method:
#RequestMapping(value = "/nomCitys/{id}",
method = RequestMethod.DELETE,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#Transactional
#Secured("ACL_NOMCITY_DELETE")
public ResponseEntity<Void> delete(#PathVariable Long id) {
nomCityRepository.delete(id);
ObjectIdentity oid = new ObjectIdentityImpl(NomCity.class,id);
mutableAclService.deleteAcl(oid, true);
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("nomCity", id.toString())).build();
}
When I create a new city all work fine, the ACL entries are created and stored in the data base, but when I go to remove a city I get a 403, although I'm logging with the user who created the city, reviewing some pages I saw the following xml entry:
<security:global-method-security
secured-annotations="enabled" access-decision-manager ref="customAccessDecisionManager" />
I suppose that it register the AccessDecisionManager but I don't know how do the same using Java Config and I don't if it's the reason of all my problems.
This question is for #secure anotation, but I finally solve the problem make a class configuration for using #Pre and #Post anotation, I post a config java class in my answer for this question.
Related
I'm working in a project apply Spring boot and JWT.
In OAuth2 configuration, I added more information into JWT sucessfully but I don't know how to extract this information when process a request contained my information.
Below is the code segment with I added my additional information:
public class CustomTokenEnhancer implements TokenEnhancer {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("user_name", authentication.getName());
User user = userService().getUserDetailsByLoginId(authentication.getName());
additionalInfo.put("user_id", user.getRelationPartId());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
If you had experienced on it, please help me to get user_id from my token when process a request.
Thanks
Finally, I got a solution, it works like a champ...
Below is some code segment, hope it help...
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public TokenEnhancer customTokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
public DefaultAccessTokenConverter customAccessTokenConverter() {
return new DefaultAccessTokenConverter();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain)
.accessTokenConverter(customAccessTokenConverter())
.authenticationManager(authenticationManager);
}
In Controller:
#Autowired
private TokenStore tokenStore;
#ApiOperation(value = "test get security data", response = String.class)
#RequestMapping(value = "/getUser1", method = RequestMethod.GET)
public #ResponseBody String getData1(OAuth2Authentication principal) {
OAuth2AuthenticationDetails auth2AuthenticationDetails = (OAuth2AuthenticationDetails) principal.getDetails();
Map<String, Object> details = tokenStore.readAccessToken(auth2AuthenticationDetails.getTokenValue()).getAdditionalInformation();
String department= (String) details.get("department");
return null;
}
I am new to both SOAP & spring boot technologies.However i have created soap webservice using below reference link.
https://spring.io/guides/gs/producing-web-service/
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
#Bean(name = "REL-6-MM7-1-4")
#Primary
public DefaultWsdl11Definition defaultWsdl11Definition() {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("MMSPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-4");
wsdl11Definition.setSchemaCollection(getXsdCollection());
return wsdl11Definition;
}
#Bean
public XsdSchemaCollection getXsdCollection() {
return new XsdSchemaCollection() {
public XsdSchema[] getXsdSchemas() {
return new XsdSchema[]{new SimpleXsdSchema(new ClassPathResource("REL-6-MM7-1-4.xsd")), new SimpleXsdSchema(new ClassPathResource("SoapEnvelope.xsd"))};
}
public XmlValidator createValidator() {
throw new UnsupportedOperationException();
}
};
}
Please find xsd posted.
This is the error that happen when you are not using the correct url into soap ui.
You need to search the right location of your XSD in the browser and make sure you can access to it.
Then you need to check the URL you are pasting into SOAP UI and see if the relative URLs actually are correct.
If they aren't, you have to use the correct location.
Edit :
In your case, I see the following code :
#Bean(name = "REL-6-MM7-1-4")
So I think that your ws is exposed at :
http://localhost:8080/ws/REL-6-MM7-1-4.wsdl
Edit 2 :
In your case, you also need to provide multiple xsd. You can do it by adding :
#Bean
public XsdSchemaCollection getXsdCollection() {
return new XsdSchemaCollection() {
public XsdSchema[] getXsdSchemas() {
return new XsdSchema[]{new SimpleXsdSchema(new ClassPathResource("REL-6-MM7-1-4.xsd")), new SimpleXsdSchema(new ClassPathResource("SoapEnvelope.xsd"))};
}
public XmlValidator createValidator() {
throw new UnsupportedOperationException();
}
};
}
and by using it at :
wsdl11Definition.setSchema(getXsdCollection());
Im having trouble using redirect functionality within my spring boot application. As shown in my code below im returning "redirect:/aucConfirm/" but when i initiate this i get a "This application has no explicit mapping" error.
#Controller
#RequestMapping("/")
public class WelcomeController {
#Autowired
AuctionItemRepository aucRepository;
// inject via application.properties
#Value("${welcome.message:test}")
private String message = "Hello World";
#RequestMapping(value = "/")
public String welcome(Map<String, Object> model) {
model.put("message", this.message);
return "welcome";
}
#RequestMapping(value = "/sell", method = RequestMethod.GET)
public String addAuction(Model model, HttpServletRequest request) {
model.addAttribute("newAuction", new AuctionItem());
return "NewAuction";
}
#RequestMapping(value = "/sell", method = RequestMethod.POST)
public String saveAuction(#ModelAttribute AuctionItem newAuction, RedirectAttributes attributes){
return "redirect:/aucConfirm";
}
#RequestMapping(value = "/aucConfirm", method = RequestMethod.GET)
public String confirmNewAuction(Model model, HttpServletRequest request) {
return "aucConfirm";
}
}
This is my current configuration class -
#SpringBootApplication
#ComponentScan
#EnableJpaRepositories("All")
#EntityScan("All")
public class AuctionWebApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AuctionWebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AuctionWebApplication.class, args);
}
#Bean
DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/auctiondb?zeroDateTimeBehavior=convertToNull");
dataSource.setUsername("root");
dataSource.setPassword("toor");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(dataSource);
entityManager.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManager.setPackagesToScan("All");
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
jpaProperties.setProperty("hibernate.hbm2ddl.auto", "update");
jpaProperties.setProperty("hibernate.id.new_generator_mappings", "false");
entityManager.setJpaProperties(jpaProperties);
return entityManager;
}
}
Update
Could it possibly have something to do with my jsp page that im trying to establish the recommit? I have a mvc form here -
<mvc:form class="form-inline" action="${action}" method="post" modelAttribute="newAuction" id="addNewAuc">
and when the user hits the next button it should hit the "redirect:/aucConfirm" -
<button type="submit" name="submit" class="btn btn-success" form="addNewAuc">Next</button>
Is there anything wrong with this code? Im running out of ideas at this point. Do i need to add anything to my spring boot configuration class to get it working? - Please help!
Update 2
http://localhost:8080/AuctionWebsite/sell
When i enter details int this form and select next i want it to redirect to-
http://localhost:8080/AuctionWebsite/aucConfirm
However this is what appears-
not redirecting at all and remaining with link http://localhost:8080/AuctionWebsite/sell
http://localhost:8080/AuctionWebsite/aucConfirm works when entered manually
Im getting a little bit desperate at this point, would really appreciate any help.
Use this code
redirect:aucConfirm
Instead of
redirect:/aucConfirm
As per your updated question. it seems that
"This application has no explicit mapping" error
Is for /error url;
The actual error is
Validation failed for object 'auctionItem'
So problem is not with redirection , it is something else related to validation. You may find specific error on console log.
I could not get this to work (with or without a '/' after the ':')...
#PostMapping("/customer/update")
public String customerUpdate(Customer customer) {
customerRepository.save(customer);
return "redirect:customer/list";
}
...so went with this...
#PostMapping("/customer/update")
public RedirectView customerUpdate(Customer customer) {
customerRepository.save(customer);
return new RedirectView("/customer/list");
}
I am using spring-ldap-core plugin in my Sprint boot application.
Basically, the LDAPTemplate - http://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/core/LdapTemplate.html
I basically want to convert the xml configuration below into java using Spring LDAP API and want to avoid using spring security.
The xml configuration that I want to convert is -
<ldap-server id="ldapServer"
url="ldap://ad.company.com:389"
manager-dn="CN=serviceaccount,OU=Service Accounts,DC=ad,DC=company,DC=com"
manager-password="password"/>
<authentication-manager>
<ldap-authentication-provider
server-ref="ldapServer"
user-search-base="dc=ad,dc=company,dc=com"
user-search-filter="sAMAccountName={0}"
group-search-filter="member={0}"
group-search-base="ou=Groups,dc=ad,dc=company,dc=com"
group-role-attribute="cn"/>
</authentication-manager>
Here is my java code below-
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.authentication.DefaultValuesAuthenticationSourceDecorator;
#Configuration
public class LdapConfiguration {
#Bean
public LdapContextSource contextSource(){
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldap://ad.company.com:389");
contextSource.setBase("DC=ad,DC=company,DC=com");
contextSource.setUserDn("CN=serviceaccount,OU=Service Accounts,DC=ad,DC=company,DC=com");
contextSource.setPassword("password");
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(){
LdapTemplate template = new LdapTemplate(contextSource());
try {
template.afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
return template;
}
}
This is how I am trying to invoke authentication -
The method that this snippet is a part of returns a boolean value if authentication happens
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("sAMAccountName", userloginName));
return ldapTemplate.authenticate("OU=Service Accounts", filter.encode(), userPassword);
This is not working and the error I get is that :
No results found for search, base: 'OU=Service Accounts'; filter: '(sAMAccountName=usernameIinput)'.
I want to know how the following xml properties can be configured using LDAP API?
group-search-filter="member={0}"
group-search-base="ou=Groups,dc=ad,dc=company,dc=com"
group-role-attribute="cn"/>
Also, what else am I missing? Why is this not working?
Any help will be really appreciated!
I was able to figure this out.
//LDAP connection using LDAPTemplate
#Configuration
public class LdapConfiguration {
#Bean
public LdapContextSource contextSource(){
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldap://companyurl.com:389");
contextSource.setUserDn("CN=serviceaccount,OU=Service Accounts,DC=ad,DC=company,DC=com");
contextSource.setPassword("secretpassword");
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(){
LdapTemplate template = new LdapTemplate(contextSource());
return template;
}
}
//Authentication portion
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("mailNickname", username));
Boolean authenticate = ldapTemplate.authenticate(base, filter.encode(), userpassword);
I'd like to create a Spring Boot ws application with two endpoints, but I need one with MTOM enabled (for newer clients) and the other with MTOM disabled (for older clients).
The two endpoints should be the same in any other way.
Please, tell me if this is possible, and if yes, give me any hints how to do it.
Thanks in advance
You can do this simply duplicating your schema and endpoint (only the namespace should differ) using the configuration below. The only limitations are that the two endpoints share the same uri (host/ws/NotMtomServices.wsdl and host/ws/MtomServices.wsdl)
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurationSupport {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
#Bean(name = "NotMtomServices")
public DefaultWsdl11Definition defaultWsdl11DefinitionILServices(XsdSchema notMtomServicesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("ILPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(NotMtomServices.NAMESPACE_URI);
wsdl11Definition.setSchema(notMtomServicesSchema);
return wsdl11Definition;
}
#Bean(name = "MtomServices")
public DefaultWsdl11Definition defaultWsdl11DefinitionILServicesMTOM(XsdSchema mtomServicesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("ILPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(MtomServices.NAMESPACE_URI);
wsdl11Definition.setSchema(mtomServicesSchema);
return wsdl11Definition;
}
#Bean
#Override
public DefaultMethodEndpointAdapter defaultMethodEndpointAdapter() {
List<MethodArgumentResolver> argumentResolvers = new ArrayList<MethodArgumentResolver>();
argumentResolvers.addAll(methodProcessors());
List<MethodReturnValueHandler> returnValueHandlers = new ArrayList<MethodReturnValueHandler>();
returnValueHandlers.addAll(methodProcessors());
DefaultMethodEndpointAdapter adapter = new DefaultMethodEndpointAdapter();
adapter.setMethodArgumentResolvers(argumentResolvers);
adapter.setMethodReturnValueHandlers(returnValueHandlers);
return adapter;
}
#Bean
public List<MarshallingPayloadMethodProcessor> methodProcessors() {
List<MarshallingPayloadMethodProcessor> retVal = new ArrayList<MarshallingPayloadMethodProcessor>();
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(NotMtomServices.NAMESPACE_URI);
marshaller.setMtomEnabled(false);
retVal.add(new MarshallingPayloadMethodProcessor(marshaller));
Jaxb2Marshaller marshallerMTOM = new Jaxb2Marshaller();
marshallerMTOM.setContextPath(MtomServices.NAMESPACE_URI);
marshallerMTOM.setMtomEnabled(true);
retVal.add(new MarshallingPayloadMethodProcessor(marshallerMTOM));
return retVal;
}
#Bean(name="notMtomServicesSchema")
public XsdSchema ServicesSchema() {
return new SimpleXsdSchema(new ClassPathResource("not_mtom_services.xsd"));
}
#Bean(name="mtomServicesSchema")
public XsdSchema ServicesSchemaMTOM() {
return new SimpleXsdSchema(new ClassPathResource("mtom_services.xsd"));
}
}