Access to HttpConduit before loading WSDL on CXF Dynamic Client - wsdl

Before loading WSDL from https URL for my dynamic client I need to set appropriate configuration on HttpConduit to avoid all SSL errors. According to docs we could hardcode conduit but not sure to do it programmatically. Is there way I could get hold of HttpConduit before creating Client object on DynamicClientFactory?
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
//Need to get HttpConduit here before the client is created, how?
Client client = dcf.createClient(wsdlUri);
// Can access http conduit only after client is created
HTTPConduit conduit = (HTTPConduit) client.getConduit();

One way to get of hold HttpConduit and customize the http(s) configuration is through HTTPConduitConfigurer. Below code snippet shows how it can be done.
Bus bus = CXFBusFactory.getThreadDefaultBus();
bus.setExtension(new HTTPConduitConfigurer() {
#Override
public void configure(String name, String address, HTTPConduit conduit) {
//set conduit parameters ...
// ex. disable host name verification
TLSClientParameters clientParameters = new TLSClientParameters();
clientParameters.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
conduit.setTlsClientParameters(clientParameters);
}
}, HTTPConduitConfigurer.class);
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(bus);
Client client = dcf.createClient(wsdlUri);

Related

non https VssConnection with access token - disable required secure connection?

using TFS in our internal network, want to programatically check in changes with an access token, but get this: InvalidOperationException Basic authentication requires a secure connection to the server. Is there a way to turn off requiring secure connection?
var basicCreds = new VssBasicCredential(string.Empty, BuildUnitTestConstants.AccessToken);
var connection = new VssConnection(new Uri(BuildUnitTestConstants.ProjectUri), basicCreds);
var sourceControlServer = connection.GetClient<TfvcHttpClient>();
Well, it is possible, albeit not recommended; I needed it as well, because internal IT department would not install TFS with HTTPS (sad story). Also, for testing scenarios it can come quite handy.
As always YMMV and I'm not responsible for what happens when you use it when you shouldn't ;-) You have been warned.
For one you could simply not use the .NET client API, but directly use HttpClient and manually put the PAT in the URL to access the REST API, e.g.:
http://<WHATEVER>:<BASE64PAT>#<instance>/_apis/...
(Hence that the tfx-cli works nicely with PATs and non-HTTPS TFS instances, most likely because it does just that internally, not using the .NET client API of course - it is a node.js thing.)
If you want to stay with the .NET client API, you can create your own credentials class like so:
using System;
using System.Linq;
using System.Net;
using Microsoft.VisualStudio.Services.Common;
namespace Utilities
{
/// <summary>
/// Same as VssBasicCredential, but doesn't throw when URL is a non SSL, i.e. http, URL.
/// </summary>
/// <inheritdoc cref="FederatedCredential"/>
internal sealed class PatCredentials : FederatedCredential
{
public PatCredentials()
: this((VssBasicToken)null)
{
}
public PatCredentials(string userName, string password)
: this(new VssBasicToken(new NetworkCredential(userName, password)))
{
}
public PatCredentials(ICredentials initialToken)
: this(new VssBasicToken(initialToken))
{
}
public PatCredentials(VssBasicToken initialToken)
: base(initialToken)
{
}
public override VssCredentialsType CredentialType => VssCredentialsType.Basic;
public override bool IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (webResponse == null ||
webResponse.StatusCode != HttpStatusCode.Found &&
webResponse.StatusCode != HttpStatusCode.Found &&
webResponse.StatusCode != HttpStatusCode.Unauthorized)
{
return false;
}
return webResponse.Headers.GetValues("WWW-Authenticate").Any(x => x.StartsWith("Basic", StringComparison.OrdinalIgnoreCase));
}
protected override IssuedTokenProvider OnCreateTokenProvider(Uri serverUrl, IHttpResponse response)
{
return new BasicAuthTokenProvider(this, serverUrl);
}
private sealed class BasicAuthTokenProvider : IssuedTokenProvider
{
public BasicAuthTokenProvider(IssuedTokenCredential credential, Uri serverUrl)
: base(credential, serverUrl, serverUrl)
{
}
protected override string AuthenticationScheme => "Basic";
public override bool GetTokenIsInteractive => this.CurrentToken == null;
}
}
}
Then create your VssCredentials using this class:
var credentials = new PatCredentials("", personalAccessToken);
var connection = new VssConnection(serverUrl, credentials);
(Shameless plug I use it in my TfsInfoService).
Nowadays you don't need to use the workaround provided by #Christian.K
Simply set the following env variable:
VSS_ALLOW_UNSAFE_BASICAUTH=true
Source: code of Microsoft.VisualStudio.Services.Common.VssBasicCredential:
protected override IssuedTokenProvider OnCreateTokenProvider(
Uri serverUrl,
IHttpResponse response)
{
bool result;
if (serverUrl.Scheme != "https" && (!bool.TryParse(Environment.GetEnvironmentVariable("VSS_ALLOW_UNSAFE_BASICAUTH") ?? "false", out result) || !result))
throw new InvalidOperationException(CommonResources.BasicAuthenticationRequiresSsl());
return (IssuedTokenProvider) new BasicAuthTokenProvider(this, serverUrl);
}
To set the environment variable programatically:
Environment.SetEnvironmentVariable("VSS_ALLOW_UNSAFE_BASICAUTH", "true")
No this is not possible. The problem of enabling PAT over unsecured connections is that anyone could intercept the token easily and would be able to use it for their own purposes.
Either enable SSL on the TSF instance, this is highly recommended. Or use Windows Authentication to use a secure form of authentication to TFS over an unsecured channel.

How is Owin able to set the Asp.Net Identity authentication cookies after the Application_EndRequest stage?

As a test, I created a fresh Asp.Net MVC5 app using the latest template in Visual Studio 2013. I added the following method to Global.asax.cs:
protected void Application_PreSendRequestHeaders()
{
Response.AppendCookie(new HttpCookie("TotalNumberOfCookiesInApplication_EndRequestIs", Response.Cookies.Count + string.Empty));
}
When I start the app and do a POST to /Account/Login using the credentials of a registered user, the cookies that get returned to the client are:
Note that the custom cookie I've added shows that there are no cookies set in the response by the time Application_PreSendRequestHeaders() is called. Despite this, all the Auth cookies arrive at the client. I was of the understanding that Application_PreSendRequestHeaders() is the last stage we can "hook" into for modifying cookies. Is the Owin middleware able to somehow add cookies after that, or am I missing something?
(In case you're interested, my motivation for all this is: I'm trying to modify the domain of the auth cookies to be ".abc.com", where "abc.com" is the last two parts of the host in the request URI. I want to do this to support authentication across multiple subdomains. Setting the CookieDomain in the context of the global Owin configuration (IAppBuilder) isn't enough because the request host changes between our debug/staging/production environments, and we often deploy the production code to Azure staging first for testing before doing a VIP swap).
(Note also that I'm aware of posts like this one, however it doesn't explain where the cookies are actually set)
EDIT:
Based on a bit more searching, it seems I'm looking into the wrong pipeline. Owin has its own pipeline, so I found this post which describes how we can hook into it. Viola...there were the cookies. Would be great if anybody could confirm that this is indeed the most sensible way to do it.
EDIT 2:
Finally decided to look into the Katana source code and found out that all I needed to do to get my cookie domains set was the following code in my CookieAuthenticationProvider
OnResponseSignIn = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
},
OnResponseSignOut = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
}
Edit 3:
An even cleaner solution for my case was just to use a custom cookie manager, which set the cookie domain based on the current request URI:
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...which is then set in the Cookie Auth Options in the Owin setup:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});
Hope that helps somebody coming across the same kind of question.
As requested by Tieson, here's a summary of my edits in the original post above, as an answer.
Suggested solution: Use a custom cookie manager.
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...which can then be set in the Cookie Auth Options in the Owin setup:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});

How to propagate spring security context to JMS?

I have a web application which sets a spring security context through a spring filter. Services are protected with spring annotations based on users roles. This works.
Asynchronous tasks are executed in JMS listeners (extend javax.jms.MessageListener). The setup of this listeners is done with Spring.
Messages are sent from the web application, at this time a user is authenticated. I need the same authentication in the JMS thread (user and roles) during message processing.
Today this is done by putting the spring authentication in the JMS ObjectMessage:
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
... put the auth object in jms message object
Then inside the JMS listener the authentication object is extracted and set in the context:
SecurityContext context = new SecurityContextImpl();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
This works most of the time. But when there is a delay before the processing of a message, message will never be processed. I couldn't determine yet the cause of these messages loss, but I'm not sure the way we propagate authentication is good, even if it works in custer when the message is processed in another server.
Is this the right way to propagate a spring authentication ?
Regards,
Mickaƫl
I did not find better solution, but this one works for me just fine.
By sending of JMS Message I'am storing Authentication as Header and respectively by receiving recreating Security Context. In order to store Authentication as Header you have to serialise it as Base64:
class AuthenticationSerializer {
static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
}
By sending just set Message header - you can create Decorator for Message Template, so that it will happen automatically. In you decorator just call such method:
private void attachAuthenticationContext(Message message){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String serialized = AuthenticationSerializer.serialize(auth);
message.setStringProperty("authcontext", serialized);
}
Receiving gets more complicated, but it can be also done automatically. Instead of applying #EnableJMS use following Configuration:
#Configuration
class JmsBootstrapConfiguration {
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JmsListenerAnnotationBeanPostProcessor jmsListenerAnnotationProcessor() {
return new JmsListenerPostProcessor();
}
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
public JmsListenerEndpointRegistry defaultJmsListenerEndpointRegistry() {
return new JmsListenerEndpointRegistry();
}
}
class JmsListenerPostProcessor extends JmsListenerAnnotationBeanPostProcessor {
#Override
protected MethodJmsListenerEndpoint createMethodJmsListenerEndpoint() {
return new ListenerEndpoint();
}
}
class ListenerEndpoint extends MethodJmsListenerEndpoint {
#Override
protected MessagingMessageListenerAdapter createMessageListenerInstance() {
return new ListenerAdapter();
}
}
class ListenerAdapter extends MessagingMessageListenerAdapter {
#Override
public void onMessage(Message jmsMessage, Session session) throws JMSException {
propagateSecurityContext(jmsMessage);
super.onMessage(jmsMessage, session);
}
private void propagateSecurityContext(Message jmsMessage) throws JMSException {
String authStr = jmsMessage.getStringProperty("authcontext");
Authentication auth = AuthenticationSerializer.deserialize(authStr);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
I have implemented for myself a different solution, which seems easier for me.
Already I have a message converter, the standard JSON Jackson message converter, which I need to configure on the JMSTemplate and the listeners.
So I created a MessageConverter implementation which wraps around another message converter, and propagates the security context via the JMS message properties.
(In my case, the propagated context is a JWT token which I can extract from the current context and apply to the security context of the listening thread).
This way the entire responsibility for propagation of security context is elegantly implemented in a single class, and requires only a little bit of configuration.
Thanks great but I am handling this in easy way . put one util file and solved .
public class AuthenticationSerializerUtil {
public static final String AUTH_CONTEXT = "authContext";
public static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
public static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
/**
* taking message and return string json from message & set current context
* #param message
* #return
*/
public static String jsonAndSetContext(Message message){
LongString authContext = (LongString)message.getMessageProperties().getHeaders().get(AUTH_CONTEXT);
Authentication auth = deserialize(authContext.toString());
SecurityContextHolder.getContext().setAuthentication(auth);
byte json[] = message.getBody();
return new String(json);
}
}

ServiceStack authentication request fails

I am trying to set up authentication with my ServiceStack service by following this tutorial.
My service is decorated with the [Authenticate] attribute.
My AppHost looks like this:
public class TestAppHost : AppHostHttpListenerBase
{
public TestAppHost() : base("TestService", typeof(TestService).Assembly) { }
public static void ConfigureAppHost(IAppHost host, Container container)
{
try
{
// Set JSON web services to return idiomatic JSON camelCase properties.
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
// Configure the IOC container
IoC.Configure(container);
// Configure ServiceStack authentication to use our custom authentication providers.
var appSettings = new AppSettings();
host.Plugins.Add(new AuthFeature(() =>
new AuthUserSession(), // use ServiceStack's session class but fill it with our own data using our own auth service provider
new IAuthProvider[] {
new UserCredentialsAuthProvider(appSettings)
}));
}
}
where UserCredentialsAuthProvider is my custom credentials provider:
public class UserCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
try
{
// Authenticate the user.
var userRepo = authService.TryResolve<IUserRepository>();
var user = userRepo.Authenticate(userName, password);
// Populate session properties.
var session = authService.GetSession();
session.IsAuthenticated = true;
session.CreatedAt = DateTime.UtcNow;
session.DisplayName = user.FullName;
session.UserAuthName = session.UserName = user.Username;
session.UserAuthId = user.ID.ToString();
}
catch (Exception ex)
{
// ... Log exception ...
return false;
}
return true;
}
}
In my user tests I initialize and start my TestAppHost on http://127.0.0.1:8888, then use JsonServiceClient to authenticate itself to the service like so:
var client = new JsonServiceClient("http://127.0.0.1:8888/")
var response = client.Send<AuthResponse>(new Auth
{
provider = UserCredentialsAuthProvider.Name,
UserName = username,
Password = password,
RememberMe = true
});
But getting the following exception:
The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at ServiceStack.ServiceClient.Web.ServiceClientBase.Send[TResponse](Object request)...
The ServiceStack.ServiceInterface.Auth.Auth request contains the correct username and passsword, and the request is being posted to:
http://127.0.0.1:8888/json/syncreply/Auth
I am not sure why the URL is not /json/auth/credentials or what I might be doing wrong. Any suggestions?
UPDATE
Tracing the chain of events up the stack I found the following:
JsonDataContractSerializer.SerializeToStream correctly serializes the Auth request into Json. However, the System.Net.HttpRequestStream passed to JsonDataContractDeserializer by EndpointHandlerBase has a stream of the correct length that is filled with nulls (zero bytes). As a result, the request object passed to CredentialsAuthProvider.Authenticate has nulls in all its properties.
How can the HTTP stream get stripped of its data?
Got it!!!
The problem was the following pre-request filter that I added for logging purposes in TestAppHost.Configure:
PreRequestFilters.Add((httpReq, httpRes) =>
{
LastRequestBody = httpReq.GetRawBody();
});
as seen here.
When the GetRawBody() method reads the request InputStream it leaves it in the EOS state, and all subsequent read attempts return nothing.
So obviously GetRawBody() can only be safely used with buffered streams, but unfortunately it quietly causes a very nasty bug instead of throwing an exception when used with a non-buffered stream.

How can I synchronize access to a private static field of a class by its methods?

I am implementing COMET in my MVC web application by using the PokiIn library for pushing notifications to clients.
Whenever a client connects, the ClientId is available in the OnClientConnected event of the CometWorker class:
public static Dictionary<int, string> clientsList
= new Dictionary<int, string>();
public static string clientId = "";
static void OnClientConnected(string clientId,
ref Dictionary<string, object> list)
{
BaseController.clientId = clientId;
}
I assign the the clientId received in the handler to the static ClientId of controller. And then when the Handler action is called, I map this ClientId to the Identity of the logged in user:-
public ActionResult Handler()
{
if (User.Identity.IsAuthenticated)
{
if (clientsList.Keys.Contains(currentUser.UserId))
clientsList[currentUser.UserId] = clientId;
else
clientsList.Add(currentUser.UserId, clientId);
}
return View();
}
Because multiple requests will be served by different threads on the server, each will access the static ClientId in both the methods.
How can I synchronize its access, so that untill one request is done with it in both the methods (OnClientConnected and Handler), the other request waits for it ?
Please tell me if my question is not clear. I will try to improve it further.
Store the clientid in the user's session not in a static variable on the controller. It needs to be in data associated with the user not the entire application. Or better yet, resolve the name/id lookup when the client connects.
I think you should use lock(clientsList){} whenever you want to update your dictionary

Resources