Apache CXF - Set HTTP header - apache

I have to set some http header fields in a Apache CXF client:
I tried it via Interceptor:
public class HttpHeaderInterceptor extends AbstractPhaseInterceptor<Message> {
private String userId;
private String xAuthorizeRoles;
private String host;
public HttpHeaderInterceptor() {
super(Phase.POST_PROTOCOL);
}
#Override
public void handleMessage(Message message) throws Fault {
Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);
try {
System.out.println("HttpHeaderInterceptor Host: " + host + " UserId: " + userId + " X-AUTHORIZE-roles: " + xAuthorizeRoles);
headers.put("Host", Collections.singletonList(host));
headers.put("UserId", Collections.singletonList(userId));
headers.put("X-AUTHORIZE-roles", Collections.singletonList(xAuthorizeRoles));
} catch (Exception ce) {
throw new Fault(ce);
}
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setxAuthorizeRoles(String xAuthorizeRoles) {
this.xAuthorizeRoles = xAuthorizeRoles;
}
public void setHost(String host) {
this.host = host;
}
}
in my dynamic client class the methode:
public void setHttHeaderInterceptor(String userId, String xAuthorizeRoles){
Client cxfClient = ClientProxy.getClient(this.abgWebServicePort);
HttpHeaderInterceptor httpHeaderInterceptor = new HttpHeaderInterceptor();
httpHeaderInterceptor.setHost("example.org");
httpHeaderInterceptor.setUserId(userId);
httpHeaderInterceptor.setxAuthorizeRoles(xAuthorizeRoles);
cxfClient.getOutInterceptors().add(httpHeaderInterceptor);
}
is called before I invoke the remote service:
For each call the userId and the xAuthorizeRoles should vary but when I inspect by calls via tcpdump all calls have the same values in the header fields.
Any ideas?

I Have solved my problem:
adding the interceptor via xml configuration:
<jaxws:client id="clientBean" serviceClass="org.example.service.ServicePortType"
address="example.org/src/service/ServicePort">
<jaxws:outInterceptors>
<bean class="org.example.interceptor.HttpHeaderInterceptor"/>
</jaxws:outInterceptors>
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
</jaxws:properties>
</jaxws:client>
in the client class I altered setHttpHeaderInterceptor to
public void setHttpHeaderInterceptor(String userId, String xAuthorizeRoles){
Client cxfClient = ClientProxy.getClient(this.servicePort);
cxfClient.getRequestContext().put("HTTP_HEADER_HOST", "example.org");
cxfClient.getRequestContext().put("HTTP_HEADER_USER_ID", userId);
cxfClient.getRequestContext().put("HTTP_HEADER_X_AUTHORIZE-ROLES", xAuthorizeRoles);
}
the interceptor class
#Override
public void handleMessage(Message message) throws Fault {
Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);
try {
headers.put("Host", Collections.singletonList(message.get("HTTP_HEADER_HOST")));
headers.put("KD_NR", Collections.singletonList(message.get("HTTP_HEADER_KD_NR")));
headers.put("X-AUTHORIZE-roles", Collections.singletonList(message.get("HTTP_HEADER_X_AUTHORIZE-ROLES")));
} catch (Exception ce) {
throw new Fault(ce);
}
}
and now it work's.
With this approach I can set HTTP-Header fields at runtime.

You should have used :Phase.POST_LOGICAL instead of Phase.POST. This worked for me

Here is a code snippet to copy a custom HTTP header (from the request) on the response in a single CXF out interceptor.
public void handleMessage(SoapMessage message) throws Fault {
// Get request HTTP headers
Map<String, List<String>> inHeaders = (Map<String, List<String>>) message.getExchange().getInMessage().get(Message.PROTOCOL_HEADERS);
// Get response HTTP headers
Map<String, List<String>> outHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
if (outHeaders == null) {
outHeaders = new HashMap<>();
message.put(Message.PROTOCOL_HEADERS, outHeaders);
}
// Copy Custom HTTP header on the response
outHeaders.put("myCustomHTTPHeader", inHeaders.get("myCustomHTTPHeader"));
}

If required to set standard HTTP header then it can be done using http conduit also.
<http-conf:conduit
name="*.http-conduit">
<http-conf:client AllowChunking="false" AcceptEncoding="gzip,deflate" Connection="Keep-Alive"
Host="myhost.com"/>
</http-conf:conduit>

Related

SoapCore Asp.net core 3.1 Header

Any idea how I can add a header for my calls using SoapCore?
what I have so far:
at startup.cs:
app.UseSoapEndpoint<IMyService>("/MyService.svc", new BasicHttpBinding(), SoapSerializer.DataContractSerializer);
in IMyService
[ServiceContract]
public interface IMyService
{
[OperationContract]
public List<SOADataGetService> GetService(string ServiceType, string ServiceName, string ServiceVersion);
}
then my soap ends up like that:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:GetService>
<tem:ServiceType>?</tem:ServiceType>
<tem:ServiceName>?</tem:ServiceName>
<tem:ServiceVersion>?</tem:ServiceVersion>
</tem:GetService>
</soapenv:Body>
</soapenv:Envelope>
I need to get in <soapenv:Header/> like user and password
You can access the header in SoapCore by implementing and registering a custom IServiceOperationTuner as described in the docs.
e.g.
public class MyServiceOperationTuner : IServiceOperationTuner
{
public void Tune(HttpContext httpContext, object serviceInstance, SoapCore.ServiceModel.OperationDescription operation)
{
if (operation.Name.Equals(nameof(MyService.SomeOperationName)))
{
MyService service = serviceInstance as MyService;
service.SetHttpRequest(httpContext.Request);
}
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IMyService, MyService>();
services.TryAddSingleton<IServiceOperationTuner>(provider => new MyServiceOperationTuner());
}
}
public class MyService : IMyService
{
private ThreadLocal<HttpRequest> _httpRequest = new ThreadLocal<HttpRequest>() { Value = null };
public void SetHttpRequest(HttpRequest request)
{
_httpRequest.Value = request;
}
public string SomeOperationName()
{
var soapHeader = GetHeaderFromRequest(_httpRequest.Value)
return $"SOAP Header: {soapHeader}";
}
private XmlNode GetHeaderFromRequest(HttpRequest request)
{
var bytes = (request.Body as MemoryStream)?.ToArray();
if (bytes == null)
{
// Body missing from request
return null;
}
var envelope = new XmlDocument();
envelope.LoadXml(Encoding.UTF8.GetString(bytes));
return envelope.DocumentElement?.ChildNodes.Cast<XmlNode>().FirstOrDefault(n => n.LocalName == "Header");
}
}
I hope this helps someone. I'm using SoapCore 1.1.0.28 with .Net Core 6. I tried the Tune method listed by #wolfyuk, but Core always returned bytes as null, so I was never able to get past the null check.
The most straightforward way I found is to use IMessageInspector2 from SoapCore to create middleware to intercept the SOAP request on the way in and intercept the SOAP response on the way out. Your class that implements IMessageInspector2 has access to the message so you can extract headers on the way in (that's what I needed), and add headers on the way out. I needed the request headers to be included in my response (a requirement of the system I'm communicating with).
public class AuthMessageFilter : IMessageInspector2
{
private const string WsNamespaceSecurityUri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private const string WsUserNameTokenNodeName = "UsernameToken";
private const string WsSecurityNodeName = "Security";
private const string WsTimestampNodeName = "Timestamp";
private readonly IMyService _service;
private readonly IHttpContextAccessor _acc;
private readonly ILogger _logger;
private MessageHeaders _messageHeaders;
public AuthMessageFilter(IHttpContextAccessor acc, IMyService service, ILogger logger)
{
_acc = acc;
_service = service;
_logger = logger;
}
public object AfterReceiveRequest(ref Message message, ServiceDescription serviceDescription)
{
ValidateSoapAction();
var token = GetUserNameToken(message);
var userIsAuthenticated = _service.ValidateUser(token.Username, token.Password.Value).GetAwaiter().GetResult();
if (userIsAuthenticated)
{
_messageHeaders = message.Headers; // use in response.
return null;
}
const string msg = "The user credentials did not authenticate.";
_logger.LogEntry(msg);
throw new AuthenticationFailedException(msg);
}
private void ValidateSoapAction()
{
try
{
var soapAction = _acc.HttpContext?.Request.Headers["SOAPAction"].FirstOrDefault()?.Replace("\"", "");
if (soapAction == null)
{
throw new Exception(
"Error: Could not extract SoapAction from HttpContext.Request.Headers. Aborting SOAP operation.");
}
}
catch (Exception ex)
{
_logger.LogEntry("No SOAP Action found.", ex);
}
}
private WsUsernameToken GetUserNameToken(Message message)
{
WsUsernameToken wsUsernameToken = null;
for (var i = 0; i < _messageHeaders.Count; i++)
{
if (!_messageHeaders[i].Name.Equals(WsSecurityNodeName, StringComparison.OrdinalIgnoreCase))
continue;
using var reader = _messageHeaders.GetReaderAtHeader(i);
while (reader.Read())
{
if (reader.IsStartElement() &&
reader.NamespaceURI.Equals(WsNamespaceSecurityUri, StringComparison.OrdinalIgnoreCase) &&
reader.LocalName.Equals(WsUserNameTokenNodeName, StringComparison.OrdinalIgnoreCase))
{
var serializer = new XmlSerializer(typeof(WsUsernameToken));
wsUsernameToken = (WsUsernameToken)serializer.Deserialize(reader);
break;
}
}
break;
}
if (wsUsernameToken == null)
{
var ex = new SecurityException("An exception occurred when verifying security for the message.");
_logger.LogEntry(LoggingCategory.Service, LoggingLevel.Error, ex.Message, ex);
throw ex;
}
return wsUsernameToken;
}
public void BeforeSendReply(ref Message reply, ServiceDescription serviceDescription, object correlationState)
{
for (var i = 0; i < _messageHeaders.Count; i++)
{
if (!_messageHeaders[i].Name.Equals(WsSecurityNodeName, StringComparison.OrdinalIgnoreCase))
continue;
using var reader = _messageHeaders.GetReaderAtHeader(i);
while (reader.Read())
{
if (reader.IsStartElement() &&
reader.NamespaceURI.Equals(WsNamespaceSecurityUri, StringComparison.OrdinalIgnoreCase) &&
reader.LocalName.Equals(WsTimestampNodeName, StringComparison.OrdinalIgnoreCase))
{
reply.Headers.Add(_messageHeaders[i] as MessageHeader);
break;
}
}
break;
}
}
}
Do not use SoapCore it is outdated, try to use SmartSoap:
https://github.com/Raffa50/SmartSoap
it is also available as a nugetPackage:
https://www.nuget.org/packages/Aldrigos.SmartSoap.AspNet/
Have a look at it, try it and if you need further support I will be pleased to help you!

How to use SoapCore in Asp.net Core project for exposing wsdl at project route folder

Your project, written with Asp.net Core, makes deploying Rest API. However, your customer wanted to communicate with soap. How to make an improvement
SoapCore has already done many things for us to support this situation. We apply step-by-step changes to our Asp.net Core project.
First in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
try
{
services.AddSoapServiceOperationTuner(new MyServiceOperationTuner());
services.Configure<XApiSettings>(options =>
{
options.baseurl = XApiOptions[nameof(XApi.baseurl)];
options.accesstokenroute = XApiOptions[nameof(XApi.accesstokenroute)];
options.secret = XApiOptions[nameof(XApi.secret)];
options.secretkey = XApiOptions[nameof(XApi.secretkey)];
options.grant_type = XApiOptions[nameof(XApi.grant_type)];
options.username = XApiOptions[nameof(XApi.username)];
options.password = XApiOptions[nameof(XApi.password)];
});
services.AddSoapCore();
services.AddSingleton<IRESAdapterService>(new RESAdapterService(
Xcontroller: new XApiController(
services.BuildServiceProvider().GetRequiredService<IOptions<XApi>>(),
_corendonLogger
)));
services.AddSoapExceptionTransformer((ex) => ex.Message);
}
catch (Exception ex)
{
Log.Logger.Error("ConfigureServices Message: " + ex.Message);
}
}
If you want your application to be accessible from the root directory at the address you deploy, you can type path '/' directly or name it as '/ XX'
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ApplicationContext dbContext)
{
try
{
app.UseSoapEndpoint<IRESAdapterService>(path: "/", binding: new BasicHttpBinding(), SoapSerializer.XmlSerializer);
}
}
In the case of requests that are handled on the server side, data sent as xml will normally be null. We need to make the following improvement in SoapCore so that the server can resolve the request.
public class MyServiceOperationTuner : IServiceOperationTuner
{
public void Tune(HttpContext httpContext, object serviceInstance, SoapCore.OperationDescription operation)
{
RESAdapterService service = serviceInstance as RESAdapterService;
service.SetHttpRequest = httpContext.Request;
}
}
In addition, the interface to meet the incoming requests and services to make redirects to our controller should write as follows
[ServiceContract]
public interface IRESAdapterService
{
[OperationContract]
[XmlSerializerFormat(SupportFaults = true)]
Task<OTA_AirAvailRS> getAvailability([FromBody]HttpRequestMessage req);
[OperationContract]
Task<OTA_AirPriceRS> pricing([FromBody]HttpRequestMessage req);
}
public class RESAdapterService : IRESAdapterService
{
XApiController _controller;
public HttpRequest SetHttpRequest { get; set; }
public RESAdapterService(XApiController XApi)
{
_controller = XApi;
}
public Task<MyRequesterClass> Method1([FromBody]HttpRequestMessage req)
{
return _controller.Method1(SetHttpRequest);
}
public Task<MyDiffRequesterClass> Method2([FromBody]HttpRequestMessage req)
{
return _controller. Method2(SetHttpRequest);
}
}
The controller was catching requests from the Request object, but; now the Request object has to get through the router service for the future of null in this context. Therefore we can implement the code that reads XML as follows
Stream reqBody = Request?.Body;
if (Request == null)
reqBody = (MyRequesterClass as HttpRequest).Body;
Let's come to the client side, write a simple framework console project
Normally we offer wsdl visual studio add references by adding the portion of the proxy can create and walk. (Recommended case) But in my case I decided to post xml with webclient because I use a user certificate and I don't know the type of object to send. Sample use below:
static string xml = " <ReqObj xmlns='http://tempuri.org/'>"
+ "</ ReqObj >";
static string wrapbody = #"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
#
</soap:Body>
</soap:Envelope>";
public static async Task<string> CreateSoapEnvelope()
{
HttpResponseMessage response = await PostXmlRequest("https://localhostorliveaddress.com");
string content = await response.Content.ReadAsStringAsync();
return content;
}
public static async Task<HttpResponseMessage> PostXmlRequest(string baseUrl)
{
X509Certificate2 clientCert = new X509Certificate2(#"D:\ccer\xxx.pfx", "password");
//X509Certificate2 clientCert = GetClientCertificate();
WebRequestHandler requestHandler = new WebRequestHandler();
requestHandler.ClientCertificates.Add(clientCert);
using (var httpClient = new HttpClient(requestHandler))
{
string wrpXmlContent = wrapbody.Replace("#", xml);
var httpContent = new StringContent(wrpXmlContent, Encoding.UTF8, "text/xml");
httpContent.Headers.Add("SOAPAction", "https://localhostorliveaddress.com/method1");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
return await httpClient.PostAsync(baseUrl, httpContent);
}
}
Getting Client certificate from My User Personel Store
private static X509Certificate2 GetClientCertificate()
{
X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
userCaStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
X509Certificate2Collection findResult = certificatesInStore.
Find(X509FindType.FindBySubjectName, "XRootCertificateOnMyUserPersonelStore", true);
X509Certificate2 clientCertificate = null;
if (findResult.Count == 1)
{
clientCertificate = findResult[0];
}
else
{
throw new Exception("Unable to locate the correct client certificate.");
}
return clientCertificate;
}
catch
{
throw;
}
finally
{
userCaStore.Close();
}
}

Spring-security/Grails app - Custom WebSecurity configurations not getting called

My project is based on Grail 2.5.6 and Spring plugins. I'm trying to create a custom auth provider, filter and token extending their respective basic classes.
this.getAuthenticationManager().authenticate(authRequest)
In my filter the authentication manager is always null. So, it throws cannot invoke authenticate() on a null object. When I debug on the authenticationManager, it lists other provider names but my custom one.
Here is my custom web security config
#Configuration
#EnableGlobalMethodSecurity(securedEnabled=true)
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
OrbisAuthenticationProvider orbisAuthenticationProvider
public CustomWebSecurityConfig() {
super()
log.debug "configure custom security"
print("configure custom security")
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
print("configure method 1")
log.debug "configure method 1"
auth.authenticationProvider(orbisAuthenticationProvider)
}
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
#Override
AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean()
}
#Bean
OrbisAuthenticationFilter orbisAuthenticationProvider() throws Exception {
log.debug "orbis Authentication provider"
OrbisAuthenticationProvider orbisAuthenticationProvider = new OrbisAuthenticationProvider(authenticationManagerBean())
return orbisAuthenticationProvider
}
#Bean
#Autowired
public OrbisAuthenticationFilter orbisAuthenticationFilter() throws Exception {
print("configure orbis filtr")
OrbisAuthenticationFilter oaf = new OrbisAuthenticationFilter()
oaf.setAuthenticationManager(authenticationManagerBean())
oaf.setFilterProcessesUrl("j_orbis_security_check")
oaf.setUsernameParameter("email")
oaf.setPasswordParameter("password")
oaf.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler()
.setDefaultTargetUrl("/oauth/authorize"))
oaf.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler()
.setDefaultFailureUrl("/loginWithOrbis"))
oaf.afterPropertiesSet()
return oaf
}
}
On debugging, it doesn't look like any of these methods are getting called. The annotations don't seem enough to get picked up. I had tried #ComponentScan too.
Do I have to inject this security config somewhere? How do I get authManager to be available in my filter?
OrbisAuthFilter
class OrbisAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
// #Autowired
OrbisAuthenticationProvider orbisAuthenticationProvider
OrbisAuthenticationFilter() {
super("/j_orbis_security_check")
orbisAuthenticationProvider = new OrbisAuthenticationProvider()
}
void afterPropertiesSet() {
assert authenticationManager != null, 'authenticationManager must be specified'
}
#Override
Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("email")
String password = request.getParameter("password")
String accessCode = request.getParameter("accessCode")
OrbisAuthenticationToken authRequestForAuthentication = new OrbisAuthenticationToken(username, password, accessCode)
// This throws error because getAuthenticationManager returns null
// authRequestForAuthentication = this.getAuthenticationManager.authenticate(authRequestForAuthentication)
//This works if I instantiate the orbis provider object in the constructor
authRequestForAuthentication = this.orbisAuthenticationProvider.authenticate(authRequestForAuthentication)
SecurityContextHolder.getContext().setAuthentication(authRequestForAuthentication)
return authRequestForAuthentication
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
#Override
#Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
}
OrbisAuthProvider
class OrbisAuthenticationProvider implements AuthenticationProvider {
#Override
Authentication authenticate(Authentication authentication) throws AuthenticationException {
OrbisAuthenticationToken orbisAuth = (OrbisAuthenticationToken) authentication
String username = orbisAuth.principal
String password = orbisAuth.credentials
String orbisAccessCode = orbisAuth.orbisAccessCode
def urlToUse = 'https://coopstatus.neu.edu/sail_api/full.aspx?' + 'ac=' + orbisAccessCode + '&e='+ username + '&p=' + password
HttpClient httpClient = DefaultHttpClient.newInstance()
HttpGet getRequest = new HttpGet(urlToUse)
HttpResponse httpResponse = httpClient.execute(getRequest)
JSONObject orbisResponse = new JSONObject(httpResponse.getEntity().getContent().getText())
// if(orbisResponse.get("IsFound")) {
// //Return error not authenticated
// }
Collection<GrantedAuthority> orbisUserGrantedAuthorities = getLDAPUserAuthorities(orbisResponse.get("Email"))
orbisAuth = new OrbisAuthenticationToken(username, password, orbisAccessCode, orbisUserGrantedAuthorities)
return orbisAuth
}
private Collection<GrantedAuthority> getLDAPUserAuthorities(String username) {
LDAPUserDetails currentLdapUserDetails
try {
currentLdapUserDetails = new LDAPUserDetailsService().loadUserByOrbisUsername(username)
log.debug currentLdapUserDetails
} catch(org.springframework.security.core.userdetails.UsernameNotFoundException e) {
log.error("User " + username + " not found in ldap", e)
}
Collection<GrantedAuthority> authorities = new ArrayList<>()
for (String authority : currentLdapUserDetails.authorities) {
authorities.add(new SimpleGrantedAuthority(authority))
}
return authorities
}
#Override
public boolean supports(Class<?> authentication) {
return (OrbisAuthenticationToken.class
.isAssignableFrom(authentication));
}
}
Resources.groovy
import edu.neu.security.OrbisAuthenticationFilter
import edu.neu.security.OrbisAuthenticationProvider
beans = {
userDetailsService(edu.neu.security.LDAPUserDetailsService)
orbisAuthenticationProvider(OrbisAuthenticationProvider)
orbisAuthenticationFilter(OrbisAuthenticationFilter) {
orbisAuthenticationProvider = ref("orbisAuthenticationProvider")
requiresAuthenticationRequestMatcher = ref('filterProcessUrlRequestMatcher')
// This throws error during startup. Unable to init bean
// authenicationManager = ref("authenicationManager")
}
myOAuth2ProviderFilter(OAuth2ProviderFilters) {
//grailsApplication = ref('grailsApplication')
// properties
}
}
I followed some of the concepts from this project: https://github.com/ppazos/cabolabs-ehrserver/
Even if the whole process is executed and securityContext is set with authenticated, when I hit oauth/authorize to get Authorization_Code, it redirects back to '/login/auth'. It still doesn't know that a user is already authenticated.
When you add an authentication provider to the AuthenticationManagerBuilder bean (which comes from AuthenticationConfiguration), the authentication manager bean you declare is not used.
Try:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled=true)
public class CustomWebSecurityConfig {
OrbisAuthenticationProvider lwoAuthProvider;
public CustomWebSecurityConfig() {
//
}
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
AuthenticationManager authenticationManagerBean() throws Exception {
return new ProviderManager(Arrays.asList(lwoAuthProvider));
}
Your AuthenticationManager bean should get picked up and will be used for method security. You can also #Autowire it in your filter if it is being managed by Spring, or #Autowire it in the #Configuration class that instantiates your filter.
NOTE: the above class WILL NOT create any of the Spring Security filters.
(The filter chain wasn't being created anyway - you didn't annotate your class with #EnableWebSecurity)

Using Dropwizard Authentication manual

I'm currently using http://www.dropwizard.io/1.1.0/docs/manual/auth.html# Dropwizard-Authentication in my Application. But i like to do the authentication "manualy" which means from a specific login/logout API call on a not authenticated REST interface.
Is there any possibility to forward an REST Call to the Authentication?
#POST
#Path("login")
#Consumes(MediaType.APPLICATION_JSON)
#Timed
#UnitOfWork
public Optional<LoginResponse> login(LoginRequest request) {
// TODO forward login request to authentication
return null;
}
Thx in advance
Thx for helping me. I found a solution like that:
Adding an Authenticator to the REST Client
client = ClientBuilder.newClient();
authenticator = new Authenticator();
client.register(authenticator);
Setup the Authenticator on Login-Successfull
final UserAPIResponse response = create(request, UserAPI.PATH_ATTRIBUTE_DEFINITION_LOGIN);
if (response == null || response.isFailed()) {
connector.setupAuthenticator(null, null);
} else {
connector.setupAuthenticator(request.getUsername(), request.getPassword());
}
And here is the Authenticator
class Authenticator implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
final MultivaluedMap<String, Object> headers = requestContext.getHeaders();
final String basicAuthentication = getBasicAuthentication();
if (basicAuthentication == null) return;
headers.add("Authorization", basicAuthentication);
}
void setup(String username, String password) {
this.user = username;
this.password = password;
}
private String getBasicAuthentication() {
if (user == null || password == null) return null;
final String token = this.user + ":" + this.password;
try {
return "BASIC " + DatatypeConverter.printBase64Binary(token.getBytes("UTF-8"));
} catch (final UnsupportedEncodingException ex) {
throw new IllegalStateException("Cannot encode with UTF-8", ex);
}
}
private String password;
private String user;
}
on the server side i have an Authenticator
public class UserAuthenticator implements Authenticator<BasicCredentials, User> {
UserAuthenticator(UserDAO userDAO) {
this.userDAO = userDAO;
}
#UnitOfWork
#Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
final String username = credentials.getUsername();
final Optional<DbUser> result = userDAO.getByName(username);
if (!result.isPresent()) return Optional.empty();
final DbUser user = result.get();
final String password = credentials.getPassword();
if (!StringUtils.equals(password, user.getPassword())) return Optional.empty();
if (!user.isOnline()) return Optional.empty();
user.handleAction();
userDAO.save(user);
return Optional.of(UserMgr.convert(user));
}
private final UserDAO userDAO;
}
And to get em working correctly:
SessionDao dao = new SessionDao(hibernateBundle.getSessionFactory());
ExampleAuthenticator exampleAuthenticator = new UnitOfWorkAwareProxyFactory(hibernateBundle)
.create(ExampleAuthenticator.class, SessionDao.class, dao);
So finally there is one REST-Call to login the User and the authentication is done on the result by the client automatically.

Cant get authentication filter working with embedded jetty

I have a REST handler servlet defined as follows (this works perfectly):
//REST handler context
ServletContextHandler restHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
restHandler.setContextPath("/");
// Jersey REST handling servlet
ServletHolder jerseyServlet = restHandler.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
// Tell Jersey which REST service class to load....
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", RestHandler.class.getCanonicalName());
I now want to add a authentication filter, which I do as:
FilterHolder authFilter = restHandler.addFilter(AuthFilter.class, "/",
EnumSet.of( DispatcherType.ASYNC,
DispatcherType.ERROR,
DispatcherType.FORWARD,
DispatcherType.INCLUDE,
DispatcherType.REQUEST));
if (authFilter == null) {
dlog.debug("Failed to load authentication filter");
};
All good so far, however, the filter does not fire on incoming REST. Calls still go through. The AuthFilter is straight from sample code:
public class AuthFilter implements javax.servlet.Filter {
private static final Logger dlog = Dlog.get();
public static final String AUTHENTICATION_HEADER = "Authorization";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filter)
throws IOException, ServletException {
dlog.entry(request, response, filter);
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authCredentials = httpServletRequest.getHeader(AUTHENTICATION_HEADER);
AuthService authenticationService = new AuthService();
boolean authenticationStatus = authenticationService.authenticate(authCredentials);
if (authenticationStatus) {
filter.doFilter(request, response);
} else {
if (response instanceof HttpServletResponse) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
dlog.exit();
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
I use handler collection as I also have a resource handler to serve static web pages besides the REST calls.
HandlerCollection handlerList = new HandlerCollection();
handlerList.setHandlers(new Handler[] { resourceHandler,
restHandler,
new DefaultHandler(),
requestLogHandler });
What else I need to do? I have scanned through number of related posts and come up empty. Thanks in advance.