Hi,
Use Case:
I used undertow and https and want to authorize at web service with username
and password defined in application.propterties.
Source Code
(RestControllerRouteBuilder.java)
// Setup
restConfiguration().apiContextRouteId("swagger")
.component("undertow")
.host("{{http.address}}")
.port("{{http.port}}")
.bindingMode(RestBindingMode.json)
.scheme("https")
.dataFormatProperty("prettyPrint", "true")
.apiContextPath("/api-doc")
.enableCORS(true)
.corsHeaderProperty("Access-Control-Allow-Headers", "Origin,
Accept, X-Requested-With, Content-Type, Access-Control-Request-Method,
Access-Control-Request-Headers, Authorization")
.apiContextPath("/v1/swagger")
.apiProperty("api.title", "Order import API")
.apiProperty("api.version", "1.0.0")
.apiProperty("cors", "true")
.endpointProperty("chunked", "true")
;
// Route
rest("/v1")
.put("/order").description("Order JSON import")
.type(Order.class)
.param().name("Authorization").type(RestParamType.header).description("The Auth
token").endParam()
.param().name("body").type(RestParamType.body).description("The
\"" + ROOT_ELEMENT + "\" as JSON").endParam()
.consumes(MediaType.APPLICATION_JSON_VALUE)
.produces(MediaType.APPLICATION_JSON_VALUE)
.responseMessage().code(HttpStatus.SC_ACCEPTED).message("<h2>No
Content</h2><p>The request has been accepted for processing, but the processing
has not been completed.</p><p>The request might or might not be eventually
acted upon, and may be disallowed when processing
occurs.</p>").endResponseMessage()
.responseMessage().code(HttpStatus.SC_BAD_REQUEST).message("<h2>Bad
Request</h2><p>Response Body Contains a JSON Object with an error message in
field \"message\"</p><h1>Example</h1><p>{\"message\" : \"Request body is
missing or not a valid JSON\"}</p>").endResponseMessage()
.responseMessage().code(HttpStatus.SC_UNAUTHORIZED).message("<h2>Not
Authorized</h2><p>No Authorization header provided</p>").endResponseMessage()
.responseMessage().code(HttpStatus.SC_FORBIDDEN).message("<h2>Not
Authorized</h2><p>You are not allowed to do this
action</p>").endResponseMessage()
.responseMessage().code(HttpStatus.SC_INTERNAL_SERVER_ERROR).message("<h2>Internal
Server Error</h2><p>Please contact the Service Provider</p><p>Response Body
Contains a JSON Object with an message in field
\"message\"</p><h1>Example</h1><p>{\"message\" : \"Validation of
'Authorization' token failed, client management service cannot be
reached.\"}</p>").endResponseMessage()
.to("direct:processRequest")
;
In ServiceRouteBuilder.java
from("direct:processRequest").routeId("responseRoute")
.log(INFO, "Request received at order import endpoint")
// check if "Authorization" header exists...
.choice()
// ... if not
.when(header(AUTHORIZATION).isNull())
.log(WARN, "No Authorization header provided")
.setHeader(HTTP_RESPONSE_CODE,
constant(HttpStatus.SC_UNAUTHORIZED))
.setBody(constant(new Document().append("message", "No
Authorization Header").toJson()))
.when().body(Order.class, order -> order == null)
.setHeader(HTTP_RESPONSE_CODE,
constant(HttpStatus.SC_UNAUTHORIZED))
.setBody(constant(new Document().append("message", "Request
Body is empty").toJson()))
.otherwise()
.setProperty(REQUEST_BODY).body(Order.class, order -> new
Document().append("order",order.getOrder()))
.to("direct:validateToken")
.endChoice()
.end()
;
from("direct:validateToken").routeId("authorizationValidationRoute")
.bean(AuthServiceHandler.class)
.to("direct:processBody")
;
from("direct:processBody").routeId("jsonBodyProcessorRoute")
// save the Order JSON into MongoDB
.setBody().exchangeProperty(REQUEST_BODY)
.to(MONGODB_INSERT)
.log(INFO, "Imported Order to MongoDB")
// send the OID of the MongoDB document to the next service via
ActiveMQ
.setBody().header(OID)
.convertBodyTo(String.class)
.to(QUEUE_PROCESS)
.log(INFO, "Processing done, message sent to " + QUEUE_PROCESS)
.log(DEBUG, "OID of MongoDB document containing Order JSON:
${header.CamelMongoOid}")
;
And try to validate by username and password
AuthServiceHandler.java
public class AuthServiceHandler {
@Autowired
private Logger logger;
private static CustomAuthenticationProvider am = new
CustomAuthenticationProvider();
@Handler
public void handler(Exchange exchange) throws Exception {
// get the username and password from the HTTP header
// http://en.wikipedia.org/wiki/Basic_access_authentication
String base64 = exchange.getIn().getHeader(AUTHORIZATION,
String.class).replace("Basic", "").trim();
String userpass = new String(Base64.decodeBase64(base64));
String[] tokens = userpass.split(":");
// create an Authentication object
//UsernamePasswordAuthenticationToken authToken = new
UsernamePasswordAuthenticationToken(tokens[0], tokens[1]);
Authentication request = new
UsernamePasswordAuthenticationToken(tokens[0], tokens[1]);
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
logger.debug("Successfully authenticated. Security context
contains: " +
SecurityContextHolder.getContext().getAuthentication());
}
}
BasicWebSecurityConfigurerAdapter,java
public class BasicWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.anyRequest()
.authenticated()
.and()
.formLogin();
}
@Override
public void configure(AuthenticationManagerBuilder builder)
throws Exception {
builder.authenticationProvider(new CustomAuthenticationProvider());
}
}
CustomAuthenticationProvider.java:
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private Logger logger;
private static List <User> users = new ArrayList();
public CustomAuthenticationProvider() {
users.add(new User(„userxxx", „passwordxxx", „xxx_USER"));
}
@Override
public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
String name = authentication.getName();
Object credentials = authentication.getCredentials();
if (!(credentials instanceof String)) {
return null;
}
String password = credentials.toString();
Optional <User> userOptional = users.stream()
.filter(u -> u.match(name, password))
.findFirst();
if (!userOptional.isPresent()) {
throw new BadCredentialsException("Authentication failed for " +
name);
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new
SimpleGrantedAuthority(userOptional.get().role));
Authentication auth = new
UsernamePasswordAuthenticationToken(name, password,
grantedAuthorities);
return auth;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
private class User {
private String name;
private String password;
private String role;
public User(String name, String password, String role) {
this.name = name;
this.password = password;
this.role = role;
}
public boolean match(String name, String password) {
return this.name.equals(name) && this.password.equals(password);
}
}
It works but I am trying to find a better solution.
Regards, Tobias