Secure using Wss4j.
This commit is contained in:
@@ -29,6 +29,11 @@
|
||||
<artifactId>spring-ws-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-ws-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-ws-test</artifactId>
|
||||
|
||||
@@ -49,8 +49,13 @@ public class GetFlights extends WebServiceGatewaySupport {
|
||||
getFlightsRequest.setDepartureDate(departureDate);
|
||||
|
||||
System.out.println("Requesting flights on " + departureDate);
|
||||
GetFlightsResponse response = (GetFlightsResponse) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequest);
|
||||
System.out.println("Got " + response.getFlight().size() + " results");
|
||||
GetFlightsResponse response = null;
|
||||
try {
|
||||
response = (GetFlightsResponse) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequest);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
System.out.println("Got " + response.getFlight().size() + " results");
|
||||
if (response.getFlight().size() > 0) {
|
||||
// Book the first flight using John Doe as a frequent flyer
|
||||
BookFlightRequest bookFlightRequest = new BookFlightRequest();
|
||||
|
||||
@@ -35,7 +35,5 @@ public class GetFrequentFlyerMileage extends WebServiceGatewaySupport {
|
||||
"<GetFrequentFlyerMileageRequest xmlns=\"http://www.springframework.org/spring-ws/samples/airline/schemas/messages\" />");
|
||||
|
||||
getWebServiceTemplate().sendSourceAndReceiveToResult(source, new StreamResult(System.out));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,5 +29,8 @@ public class SpringWsMain {
|
||||
|
||||
GetFlights getFlights = ctx.getBean(GetFlights.class);
|
||||
getFlights.getFlights();
|
||||
|
||||
GetFrequentFlyerMileage getFrequentFlyerMileage = ctx.getBean(GetFrequentFlyerMileage.class);
|
||||
getFrequentFlyerMileage.getFrequentFlyerMileage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package org.springframework.ws.samples.airline.client.sws;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
|
||||
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
|
||||
import org.springframework.ws.soap.SoapMessageFactory;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class WsConfiguration {
|
||||
@@ -23,7 +25,8 @@ public class WsConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
GetFlights getFlights(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller) {
|
||||
GetFlights getFlights(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller,
|
||||
Wss4jSecurityInterceptor securityInterceptor) {
|
||||
|
||||
GetFlights getFlights = new GetFlights(messageFactory);
|
||||
getFlights.setDefaultUri("http://localhost:8080/airline-server/services");
|
||||
@@ -33,10 +36,24 @@ public class WsConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
GetFrequentFlyerMileage getFrequentFlyerMileage(SoapMessageFactory messageFactory) {
|
||||
GetFrequentFlyerMileage getFrequentFlyerMileage(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller,
|
||||
Wss4jSecurityInterceptor securityInterceptor) {
|
||||
|
||||
GetFrequentFlyerMileage getFrequentFlyerMileage = new GetFrequentFlyerMileage(messageFactory);
|
||||
getFrequentFlyerMileage.setDefaultUri("http://localhost:8080/airline-server/services");
|
||||
getFrequentFlyerMileage.setMarshaller(marshaller);
|
||||
getFrequentFlyerMileage.setUnmarshaller(marshaller);
|
||||
getFrequentFlyerMileage.setInterceptors(new ClientInterceptor[] { securityInterceptor });
|
||||
return getFrequentFlyerMileage;
|
||||
}
|
||||
|
||||
@Bean
|
||||
Wss4jSecurityInterceptor securityInterceptor() {
|
||||
|
||||
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
|
||||
securityInterceptor.setSecurementActions("UsernameToken");
|
||||
securityInterceptor.setSecurementUsername("john");
|
||||
securityInterceptor.setSecurementPassword("changeme");
|
||||
return securityInterceptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,16 +36,15 @@
|
||||
<artifactId>spring-boot-starter-web-services</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.ws</groupId>-->
|
||||
<!-- <artifactId>spring-ws-security</artifactId>-->
|
||||
<!-- <exclusions>-->
|
||||
<!-- <exclusion>-->
|
||||
<!-- <groupId>com.sun.xml.wsit</groupId>-->
|
||||
<!-- <artifactId>wsit-rt</artifactId>-->
|
||||
<!-- </exclusion>-->
|
||||
<!-- </exclusions>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-ws-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
|
||||
@@ -2,8 +2,9 @@ package org.springframework.ws.samples.airline;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
|
||||
public class AirlineServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -35,12 +35,4 @@ public interface FlightDao extends CrudRepository<Flight, Long> {
|
||||
@Param("class") ServiceClass serviceClass);
|
||||
|
||||
Flight findFlightByNumberAndDepartureTime(String flightNumber, ZonedDateTime departureTime);
|
||||
|
||||
/**
|
||||
* @deprecated Migrate to {@link #save(Object)}.
|
||||
*/
|
||||
@Deprecated
|
||||
default Flight update(Flight flight) {
|
||||
return save(flight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,13 @@
|
||||
|
||||
package org.springframework.ws.samples.airline.dao;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
|
||||
public interface FrequentFlyerDao extends CrudRepository<FrequentFlyer, Long> {
|
||||
|
||||
/**
|
||||
* @deprecated Migrate to {@link #findByUsername(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
default FrequentFlyer get(String username) throws DataAccessException {
|
||||
return findByUsername(username);
|
||||
}
|
||||
|
||||
FrequentFlyer findByUsername(String username);
|
||||
Optional<FrequentFlyer> findByUsername(String username);
|
||||
|
||||
}
|
||||
|
||||
@@ -85,8 +85,10 @@ public class FrequentFlyer extends Passenger {
|
||||
return username.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return username;
|
||||
return "FrequentFlyer{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", miles=" + miles
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public void addMiles(int miles) {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.springframework.ws.samples.airline.security;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
|
||||
public class FrequentFlyerDetails implements UserDetails {
|
||||
|
||||
private static final List<GrantedAuthority> GRANTED_AUTHORITIES = List
|
||||
.of(new SimpleGrantedAuthority("ROLE_FREQUENT_FLYER"));
|
||||
|
||||
private FrequentFlyer frequentFlyer;
|
||||
|
||||
public FrequentFlyerDetails(FrequentFlyer frequentFlyer) {
|
||||
this.frequentFlyer = frequentFlyer;
|
||||
}
|
||||
|
||||
public FrequentFlyer getFrequentFlyer() {
|
||||
return frequentFlyer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return GRANTED_AUTHORITIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return frequentFlyer.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return frequentFlyer.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FrequentFlyerDetails{" + "frequentFlyer=" + frequentFlyer + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.springframework.ws.samples.airline.security;
|
||||
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
|
||||
|
||||
/**
|
||||
* Defines the business logic for handling frequent flyers.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public interface FrequentFlyerSecurityService {
|
||||
|
||||
/**
|
||||
* Returns the <code>FrequentFlyer</code> with the given username.
|
||||
*
|
||||
* @param username the username
|
||||
* @return the frequent flyer with the given username, or <code>null</code> if not found
|
||||
* @throws NoSuchFrequentFlyerException when the frequent flyer cannot be found
|
||||
*/
|
||||
FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException;
|
||||
|
||||
/**
|
||||
* Returns the <code>FrequentFlyer</code> that is currently logged in.
|
||||
*
|
||||
* @return the frequent flyer that is currently logged in, or <code>null</code> if not found
|
||||
*/
|
||||
FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.springframework.ws.samples.airline.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.ws.samples.airline.dao.FrequentFlyerDao;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMethodSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
SpringSecurityFrequentFlyerService userDetailsService(FrequentFlyerDao frequentFlyerDao) {
|
||||
return new SpringSecurityFrequentFlyerService(frequentFlyerDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
PasswordEncoder passwordEncoder() {
|
||||
return NoOpPasswordEncoder.getInstance();
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
|
||||
//
|
||||
// security.authorizeHttpRequests() //
|
||||
// .requestMatchers("/login", "/error", "/logout").permitAll() //
|
||||
// .anyRequest().authenticated() //
|
||||
// .and() //
|
||||
// .csrf().disable();
|
||||
//
|
||||
// return security.build();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.springframework.ws.samples.airline.security;
|
||||
|
||||
import org.apache.wss4j.common.principal.UsernameTokenPrincipal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.ws.samples.airline.dao.FrequentFlyerDao;
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link FrequentFlyerSecurityService} that uses Spring Security.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class SpringSecurityFrequentFlyerService implements FrequentFlyerSecurityService, UserDetailsService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringSecurityFrequentFlyerService.class);
|
||||
|
||||
private final FrequentFlyerDao frequentFlyerDao;
|
||||
|
||||
public SpringSecurityFrequentFlyerService(FrequentFlyerDao frequentFlyerDao) {
|
||||
this.frequentFlyerDao = frequentFlyerDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException {
|
||||
return frequentFlyerDao.findByUsername(username) //
|
||||
.orElseThrow(() -> new NoSuchFrequentFlyerException(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication != null) {
|
||||
UsernameTokenPrincipal principal = (UsernameTokenPrincipal) authentication.getPrincipal();
|
||||
FrequentFlyerDetails frequentFlyerDetails = (FrequentFlyerDetails) loadUserByUsername(principal.getName());
|
||||
return frequentFlyerDetails.getFrequentFlyer();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
log.debug("Looking up " + username);
|
||||
|
||||
FrequentFlyerDetails details = frequentFlyerDao.findByUsername(username) //
|
||||
.map(FrequentFlyerDetails::new) //
|
||||
.orElseThrow(() -> new UsernameNotFoundException("Frequent flyer '" + username + "' not found"));
|
||||
|
||||
log.debug("Found " + details);
|
||||
|
||||
return details;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.springframework.ws.samples.airline.security;
|
||||
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
|
||||
|
||||
/**
|
||||
* Stub implementation of <code>FrequentFlyerSecurityService</code>. This implementation is used by default by
|
||||
* {@link org.springframework.ws.samples.airline.service.impl.AirlineServiceImpl}, to allow it to run without depending
|
||||
* on Spring Security.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class StubFrequentFlyerSecurityService implements FrequentFlyerSecurityService {
|
||||
|
||||
private FrequentFlyer john;
|
||||
|
||||
public StubFrequentFlyerSecurityService() {
|
||||
this.john = new FrequentFlyer("John", "Doe", "john", "changeme");
|
||||
john.setMiles(10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException {
|
||||
if (john.getUsername().equals(username)) {
|
||||
return john;
|
||||
} else {
|
||||
throw new NoSuchFrequentFlyerException(username);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
|
||||
return john;
|
||||
}
|
||||
}
|
||||
@@ -66,4 +66,11 @@ public interface AirlineService {
|
||||
Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List<Passenger> passengers)
|
||||
throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException;
|
||||
|
||||
/**
|
||||
* Returns the amount of frequent flyer award miles for the currently logged in frequent flyer.
|
||||
*
|
||||
* @return the amount of frequent flyer miles
|
||||
*/
|
||||
int getFrequentFlyerMileage();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,19 +18,20 @@ package org.springframework.ws.samples.airline.service.impl;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.samples.airline.dao.FlightDao;
|
||||
import org.springframework.ws.samples.airline.dao.TicketDao;
|
||||
import org.springframework.ws.samples.airline.domain.Flight;
|
||||
import org.springframework.ws.samples.airline.domain.Passenger;
|
||||
import org.springframework.ws.samples.airline.domain.ServiceClass;
|
||||
import org.springframework.ws.samples.airline.domain.Ticket;
|
||||
import org.springframework.ws.samples.airline.domain.*;
|
||||
import org.springframework.ws.samples.airline.security.FrequentFlyerSecurityService;
|
||||
import org.springframework.ws.samples.airline.security.StubFrequentFlyerSecurityService;
|
||||
import org.springframework.ws.samples.airline.service.AirlineService;
|
||||
import org.springframework.ws.samples.airline.service.NoSeatAvailableException;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFlightException;
|
||||
@@ -51,40 +52,66 @@ public class AirlineServiceImpl implements AirlineService {
|
||||
|
||||
private TicketDao ticketDao;
|
||||
|
||||
@Autowired
|
||||
private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService();
|
||||
|
||||
public AirlineServiceImpl(FlightDao flightDao, TicketDao ticketDao) {
|
||||
|
||||
this.flightDao = flightDao;
|
||||
this.ticketDao = ticketDao;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setFrequentFlyerSecurityService(FrequentFlyerSecurityService frequentFlyerSecurityService) {
|
||||
this.frequentFlyerSecurityService = frequentFlyerSecurityService;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = false,
|
||||
rollbackFor = { NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class })
|
||||
public Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List<Passenger> passengers)
|
||||
throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException {
|
||||
|
||||
Assert.notEmpty(passengers, "No passengers given");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Booking flight '" + flightNumber + "' on '" + departureTime + "' for " + passengers);
|
||||
}
|
||||
|
||||
Flight flight = flightDao.findFlightByNumberAndDepartureTime(flightNumber, departureTime);
|
||||
|
||||
if (flight == null) {
|
||||
throw new NoSuchFlightException(flightNumber, departureTime);
|
||||
} else if (flight.getSeatsAvailable() < passengers.size()) {
|
||||
throw new NoSeatAvailableException(flight);
|
||||
}
|
||||
|
||||
Ticket ticket = new Ticket();
|
||||
ticket.setIssueDate(LocalDate.now());
|
||||
ticket.setFlight(flight);
|
||||
passengers.forEach(ticket::addPassenger);
|
||||
|
||||
for (Passenger passenger : passengers) {
|
||||
if (passenger instanceof FrequentFlyer && frequentFlyerSecurityService != null) {
|
||||
String username = ((FrequentFlyer) passenger).getUsername();
|
||||
Assert.hasLength(username, "No username specified");
|
||||
FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getFrequentFlyer(username);
|
||||
frequentFlyer.addMiles(flight.getMiles());
|
||||
ticket.addPassenger(frequentFlyer);
|
||||
} else {
|
||||
ticket.addPassenger(passenger);
|
||||
}
|
||||
}
|
||||
|
||||
flight.substractSeats(passengers.size());
|
||||
|
||||
flightDao.save(flight);
|
||||
ticketDao.save(ticket);
|
||||
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public Flight getFlight(Long id) throws NoSuchFlightException {
|
||||
return flightDao.findById(id).orElseThrow(() -> new NoSuchFlightException(id));
|
||||
|
||||
return flightDao.findById(id) //
|
||||
.orElseThrow(() -> new NoSuchFlightException(id));
|
||||
}
|
||||
|
||||
public List<Flight> getFlights(String fromAirportCode, String toAirportCode, ZonedDateTime departureDate,
|
||||
@@ -93,13 +120,30 @@ public class AirlineServiceImpl implements AirlineService {
|
||||
if (serviceClass == null) {
|
||||
serviceClass = ServiceClass.ECONOMY;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Getting flights from '" + fromAirportCode + "' to '" + toAirportCode + "' on " + departureDate);
|
||||
}
|
||||
|
||||
List<Flight> flights = flightDao.findFlights(fromAirportCode, toAirportCode, departureDate, serviceClass);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning " + flights.size() + " flights");
|
||||
}
|
||||
|
||||
return flights;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasRole('FREQUENT_FLYER')")
|
||||
public int getFrequentFlyerMileage() {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + frequentFlyerSecurityService + " for security");
|
||||
}
|
||||
|
||||
return Optional.ofNullable(frequentFlyerSecurityService.getCurrentlyAuthenticatedFrequentFlyer())
|
||||
.map(FrequentFlyer::getMiles) //
|
||||
.orElse(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.time.LocalDate;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -49,7 +49,7 @@ public class FlightsController {
|
||||
public String flightList(@RequestParam(value = "from", required = false) String fromAirportCode,
|
||||
@RequestParam(value = "to", required = false) String toAirportCode,
|
||||
@RequestParam(value = "departureDate", required = false) String departureDateString,
|
||||
@RequestParam(value = "serviceClass", required = false) String serviceClassString, ModelMap model) {
|
||||
@RequestParam(value = "serviceClass", required = false) String serviceClassString, Model model) {
|
||||
|
||||
if (ObjectUtils.isEmpty(departureDateString)) {
|
||||
departureDateString = LocalDate.now().toString();
|
||||
@@ -58,7 +58,7 @@ public class FlightsController {
|
||||
serviceClassString = "ECONOMY";
|
||||
}
|
||||
ServiceClass serviceClass = ServiceClass.valueOf(serviceClassString);
|
||||
ZonedDateTime departureDate = ZonedDateTime.parse(departureDateString);
|
||||
ZonedDateTime departureDate = ZonedDateTime.parse(departureDateString);
|
||||
|
||||
if (StringUtils.hasLength(fromAirportCode) && StringUtils.hasLength(toAirportCode)) {
|
||||
model.addAttribute("from", fromAirportCode);
|
||||
@@ -72,7 +72,7 @@ public class FlightsController {
|
||||
}
|
||||
|
||||
@GetMapping(value = "{id}")
|
||||
public String singleFlight(@PathVariable("id") long id, ModelMap model) throws NoSuchFlightException {
|
||||
public String singleFlight(@PathVariable("id") long id, Model model) throws NoSuchFlightException {
|
||||
|
||||
model.addAttribute(airlineService.getFlight(id));
|
||||
return "flight";
|
||||
|
||||
@@ -24,15 +24,16 @@ import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
|
||||
@@ -45,6 +46,8 @@ import org.springframework.ws.samples.airline.service.NoSeatAvailableException;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFlightException;
|
||||
import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
|
||||
import org.springframework.ws.server.endpoint.annotation.*;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Endpoint that handles the Airline Web Service messages using a combination of JAXB2 marshalling and XPath
|
||||
@@ -55,7 +58,7 @@ import org.springframework.ws.server.endpoint.annotation.*;
|
||||
@Endpoint
|
||||
public class AirlineEndpoint {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AirlineEndpoint.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(AirlineEndpoint.class);
|
||||
|
||||
private final ObjectFactory objectFactory = new ObjectFactory();
|
||||
|
||||
@@ -136,23 +139,38 @@ public class AirlineEndpoint {
|
||||
NoSuchFrequentFlyerException, DatatypeConfigurationException {
|
||||
|
||||
ZonedDateTime departureTime = SchemaConversionUtils.toDateTime(xmlDepartureTime);
|
||||
List<Passenger> passengers = new ArrayList<Passenger>(passengerOrUsernameList.size());
|
||||
List<Passenger> passengers = new ArrayList<>(passengerOrUsernameList.size());
|
||||
|
||||
for (Iterator<Object> iterator = passengerOrUsernameList.iterator(); iterator.hasNext();) {
|
||||
Object passengerOrUsername = iterator.next();
|
||||
if (passengerOrUsername instanceof Name) {
|
||||
Name passengerName = (Name) passengerOrUsername;
|
||||
for (Object passengerOrUsername : passengerOrUsernameList) {
|
||||
if (passengerOrUsername instanceof Name passengerName) {
|
||||
Passenger passenger = new Passenger(passengerName.getFirst(), passengerName.getLast());
|
||||
passengers.add(passenger);
|
||||
} else if (passengerOrUsername instanceof String) {
|
||||
String frequentFlyerUsername = (String) passengerOrUsername;
|
||||
} else if (passengerOrUsername instanceof String frequentFlyerUsername) {
|
||||
FrequentFlyer frequentFlyer = new FrequentFlyer(frequentFlyerUsername);
|
||||
passengers.add(frequentFlyer);
|
||||
}
|
||||
}
|
||||
|
||||
org.springframework.ws.samples.airline.domain.Ticket domainTicket = airlineService.bookFlight(flightNumber,
|
||||
departureTime, passengers);
|
||||
|
||||
return SchemaConversionUtils.toSchemaType(domainTicket);
|
||||
}
|
||||
|
||||
@PayloadRoot(localPart = GET_FREQUENT_FLYER_MILEAGE_REQUEST, namespace = MESSAGES_NAMESPACE)
|
||||
@ResponsePayload
|
||||
public Element getFrequentFlyerMileage() throws ParserConfigurationException {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received GetFrequentFlyerMileageRequest");
|
||||
}
|
||||
|
||||
int mileage = airlineService.getFrequentFlyerMileage();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = documentBuilder.newDocument();
|
||||
Element response = document.createElementNS(MESSAGES_NAMESPACE, GET_FREQUENT_FLYER_MILEAGE_RESPONSE);
|
||||
response.setTextContent(Integer.toString(mileage));
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.springframework.ws.samples.airline.ws;
|
||||
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
|
||||
import org.springframework.boot.web.server.MimeMappings;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
@@ -8,10 +10,13 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
|
||||
import org.springframework.ws.soap.security.wss4j2.callback.SpringSecurityPasswordValidationCallbackHandler;
|
||||
import org.springframework.ws.soap.server.SoapMessageDispatcher;
|
||||
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadRootSmartSoapEndpointInterceptor;
|
||||
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
|
||||
import org.springframework.ws.transport.http.MessageDispatcherServlet;
|
||||
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
|
||||
@@ -40,11 +45,6 @@ public class WebServicesConfiguration {
|
||||
return new ServletRegistrationBean<>(messageDispatcherServlet, "/airline-server/*", "*.wsdl");
|
||||
}
|
||||
|
||||
@Bean
|
||||
PayloadLoggingInterceptor payloadLoggingInterceptor() {
|
||||
return new PayloadLoggingInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PayloadValidatingInterceptor payloadValidatingInterceptor(CommonsXsdSchemaCollection xsdSchemaCollection) {
|
||||
|
||||
@@ -56,33 +56,34 @@ public class WebServicesConfiguration {
|
||||
return payloadValidatingInterceptor;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// XwsSecurityInterceptor securityInterceptor(UserDetailsService securityService) {
|
||||
//
|
||||
// XwsSecurityInterceptor securityInterceptor = new XwsSecurityInterceptor();
|
||||
// securityInterceptor.setSecureResponse(false);
|
||||
// securityInterceptor.setPolicyConfiguration(
|
||||
// new ClassPathResource("org/springframework/ws/samples/airline/security/securityPolicy.xml"));
|
||||
// securityInterceptor.setCallbackHandler(springDigestPasswordValidationCallbackHandler(securityService));
|
||||
//
|
||||
// return securityInterceptor;
|
||||
// }
|
||||
@Bean
|
||||
Wss4jSecurityInterceptor securityInterceptor(SpringSecurityPasswordValidationCallbackHandler handler) {
|
||||
|
||||
// @Bean
|
||||
// PayloadRootSmartSoapEndpointInterceptor smartSoapEndpointInterceptor(XwsSecurityInterceptor securityInterceptor) {
|
||||
//
|
||||
// return new PayloadRootSmartSoapEndpointInterceptor(securityInterceptor,
|
||||
// "http://www.springframework.org/spring-ws/samples/airline/schemas/messages", "GetFrequentFlyerMileageRequest");
|
||||
// }
|
||||
/**
|
||||
* <xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
* <xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/> </xwss:SecurityConfiguration>
|
||||
*/
|
||||
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
|
||||
securityInterceptor.setValidationActions("UsernameToken");
|
||||
securityInterceptor.setValidationCallbackHandlers(new CallbackHandler[] { handler });
|
||||
securityInterceptor.setSecureResponse(false);
|
||||
return securityInterceptor;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// SpringDigestPasswordValidationCallbackHandler springDigestPasswordValidationCallbackHandler(
|
||||
// UserDetailsService securityService) {
|
||||
//
|
||||
// SpringDigestPasswordValidationCallbackHandler handler = new SpringDigestPasswordValidationCallbackHandler();
|
||||
// handler.setUserDetailsService(securityService);
|
||||
// return handler;
|
||||
// }
|
||||
@Bean
|
||||
PayloadRootSmartSoapEndpointInterceptor smartSoapEndpointInterceptor(Wss4jSecurityInterceptor securityInterceptor) {
|
||||
return new PayloadRootSmartSoapEndpointInterceptor(securityInterceptor,
|
||||
"http://www.springframework.org/spring-ws/samples/airline/schemas/messages", "GetFrequentFlyerMileageRequest");
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringSecurityPasswordValidationCallbackHandler springSecurityPasswordValidationCallbackHandler(
|
||||
UserDetailsService userDetailsService) {
|
||||
|
||||
SpringSecurityPasswordValidationCallbackHandler handler = new SpringSecurityPasswordValidationCallbackHandler();
|
||||
handler.setUserDetailsService(userDetailsService);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
SaajSoapMessageFactory messageFactory() {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
logging.level.org.springframework.data=DEBUG
|
||||
logging.level.org.springframework.web=DEBUG
|
||||
logging.level.org.springframework.web=TRACE
|
||||
logging.level.org.springframework.jms=DEBUG
|
||||
logging.level.org.springframework.ws=DEBUG
|
||||
logging.level.org.springframework.security=TRACE
|
||||
#logging.level.org.apache.activemq=DEBUG
|
||||
logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG
|
||||
logging.level.org.springframework.ws.server.MessageTracing.sent=DEBUG
|
||||
logging.level.org.springframework.ws.client.MessageTracing.received=TRACE
|
||||
logging.level.org.springframework.ws.server.MessageTracing.received=TRACE
|
||||
logging.level.org.springframework.ws.samples=DEBUG
|
||||
|
||||
Reference in New Issue
Block a user