Proxy with CefSharp - vb.net

how can I set up a proxy that has username and password in CefSharp browser in visual basic?
I tried with this code but doesn't work:
Dim proxy = "IP:PORT#USERNAME:PASSWORD"
Dim settings As New CefSettings()
settings.CefCommandLineArgs.Add("proxy-server", proxy)
Thanks

Your browser implement a IBrowser interface with GetHost method that allow you get RequestContext. You can set the proxy:
var requestContext = browser.GetHost().RequestContext;
var values = new Dictionary<string, object>
{
["mode"] = "fixed_servers",
["server"] = $"{proxyScheme}://{proxyHost}:{proxyPort}"
};
string error;
bool success = requestContext.SetPreference("proxy", values, out error);
To set user/password, you need to implement an IRequestHandler interface and implement this method:
public bool GetAuthCredentials(
IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
{
if (isProxy)
{
var browser2 = browserControl as IChromeRequestHandler;
var proxyOptions = browser2?.ProxySettings;
if (proxyOptions != null)
{
callback.Continue(proxyOptions.UserName, proxyOptions.Password);
return true;
}
}
callback.Dispose();
return false;
}
Then, you must set the RequestHandler property of your browser:
browser.RequestHandler = new YourIRequestHandlerImplementation();
Sorry for the C# implementation, but I think may be useful to you.

Related

MvvmCross HTTP DownloadCache with authentication

In my app, the user need to be authenticated on the server to download data using WebAPIs.
The MvvmCross DownloadCache plugin seems to handle only basic HTTP GET queries. I can't add my authentication token in the url as it's a big SAML token.
How can I add a HTTP header to queries done through DownloadCache plugin ?
With the current version I think I should inject my own IMvxHttpFileDownloader but I'm looking for an easier solution. Injecting my own MvxFileDownloadRequest would be better (not perfect) but it doesn't have an interface...
I'm able to do it registering a custom IWebRequestCreate for a custom scheme (http-auth://).
It's a bit ugly to transform urls from my datasource but it does the job.
public class AuthenticationWebRequestCreate : IWebRequestCreate
{
public const string HttpPrefix = "http-auth";
public const string HttpsPrefix = "https-auth";
private static string EncodeCredential(string userName, string password)
{
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string credential = userName + ":" + password;
return Convert.ToBase64String(encoding.GetBytes(credential));
}
public static void RegisterBasicAuthentication(string userName, string password)
{
var authenticateValue = "Basic " + EncodeCredential(userName, password);
AuthenticationWebRequestCreate requestCreate = new AuthenticationWebRequestCreate(authenticateValue);
Register(requestCreate);
}
public static void RegisterSamlAuthentication(string token)
{
var authenticateValue = "SAML2 " + token;
AuthenticationWebRequestCreate requestCreate = new AuthenticationWebRequestCreate(authenticateValue);
Register(requestCreate);
}
private static void Register(AuthenticationWebRequestCreate authenticationWebRequestCreate)
{
WebRequest.RegisterPrefix(HttpPrefix, authenticationWebRequestCreate);
WebRequest.RegisterPrefix(HttpsPrefix, authenticationWebRequestCreate);
}
private readonly string _authenticateValue;
public AuthenticationWebRequestCreate(string authenticateValue)
{
_authenticateValue = authenticateValue;
}
public WebRequest Create(System.Uri uri)
{
UriBuilder uriBuilder = new UriBuilder(uri);
switch (uriBuilder.Scheme)
{
case HttpPrefix:
uriBuilder.Scheme = "http";
break;
case HttpsPrefix:
uriBuilder.Scheme = "https";
break;
default:
break;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriBuilder.Uri);
request.Headers[HttpRequestHeader.Authorization] = _authenticateValue;
return request;
}
}

Using OAuthWebSecurity with Salesforce

I'm trying to get an ASP.NET MVC site to accept Salesforce as an authentication provider, but I am not having any luck. I'll start out with the IAuthenticationClient I have so far:
public class SalesForceOAuth2Client : OAuth2Client
{
private readonly String consumerKey;
private readonly String consumerSecret;
#if DEBUG
private const String BaseEndpoint = #"https://test.salesforce.com";
#else
private const String BaseEndpoint = #"https://login.salesforce.com";
#endif
private const String AuthorizeEndpoint = BaseEndpoint + #"/services/oauth2/authorize";
private const String TokenEndpoint = BaseEndpoint + #"/services/oauth2/token";
private const String RevokeEndpoint = BaseEndpoint + #"/services/oauth2/revoke";
public SalesForceOAuth2Client(String consumerKey, String consumerSecret)
: base("SalesForce")
{
if (String.IsNullOrWhiteSpace(consumerKey))
{
throw new ArgumentNullException("consumerKey");
}
if (String.IsNullOrWhiteSpace(consumerSecret))
{
throw new ArgumentNullException("consumerSecret");
}
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
}
protected override Uri GetServiceLoginUrl(Uri returnUrl)
{
String redirect_url = returnUrl.AbsoluteUri;
// Hack to work-around the __provider__ & __sid__ query parameters,
// but it is ultimately useless.
/*String state = String.Empty;
Int32 q = redirect_url.IndexOf('?');
if (q != -1)
{
state = redirect_url.Substring(q + 1);
redirect_url = redirect_url.Substring(0, q);
}*/
var builder = new UriBuilder(AuthorizeEndpoint);
builder.Query = "response_type=code"
+ "&client_id=" + HttpUtility.UrlEncode(this.consumerKey)
+ "&scope=full"
+ "&redirect_uri=" + HttpUtility.UrlEncode(redirect_url)
// Part of the above hack (tried to use `state` parameter)
/*+ (!String.IsNullOrWhiteSpace(state) ? "&state=" + HttpUtility.UrlEncode(state) : String.Empty)*/;
return builder.Uri;
}
protected override IDictionary<String, String> GetUserData(String accessToken)
{
// I am not sure how to get this yet as everything concrete I've
// seen uses the service's getUserInfo call (but this service relies
// heavily on a username, password, token combination. The whole point
// of using oatuh is to avoid asking the user for his/her credentials)
// more information about the original call:
// http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_getuserinfo.htm
// Return static information for now
//TODO: Get information dynamically
return new Dictionary<String, String>
{
{ "username", "BradChristie" },
{ "name", "Brad Christie" }
};
}
protected override String QueryAccessToken(Uri returnUrl, String authorizationCode)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(TokenEndpoint);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
using (StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream()))
{
streamWriter.Write("grant_type=authorization_code");
streamWriter.Write("&client_id=" + HttpUtility.UrlEncode(this.consumerKey));
streamWriter.Write("&client_secret=" + HttpUtility.UrlEncode(this.consumerSecret));
streamWriter.Write("&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.AbsoluteUri));
streamWriter.Write("&code=" + HttpUtility.UrlEncode(authorizationCode));
streamWriter.Flush();
}
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
if (webResponse.StatusCode == HttpStatusCode.OK)
{
using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()))
{
String response = streamReader.ReadToEnd();
var queryString = HttpUtility.ParseQueryString(response);
return queryString["access_token"];
}
}
return String.Empty;
}
}
The primary problem is that redirect_uri != Callback Url.
Salesforce enforces the callback URL you supply in the application configuration to match exactly to the value provided in redirect_uri of QueryAccessToken. Unfortunately OAuthWebSecurity relies on DotNetOpenAuth.AspNet, and that library appends two query parameters: __provider__ and __sid__. If I try to remove those (see the hack in GetServiceLoginUrl), obviously the login fails because the hand-back doesn't know how to continue on with the request without knowing which provider to use.
To work around this I did notice that the request call accepts an optional state parameter which is (essentially) there for passing things back and forth across the request/callback. However, with the dependence on __provider__ and __sid__ being their own keys having data=__provider__%3DSalesForce%26__sid__%3D1234567890 is useless.
Is there a work-around without having to fork/recompile the Microsoft.Web.WebPages.OAuth library and modify the OAuthWebSecurity.VerifyAuthenticationCore(HttpContextBase, String) method to look at data first, then continue on to OpenAuthSecurityMananer.GetProviderName?
Also, in case the registration mattered (AuthConfig.cs):
OAuthWebSecurity.RegisterClient(
new SalesForceOAuth2Client(/*consumerKey*/, /*consumerSecret*/),
"SalesForce",
new Dictionary<String, Object>()
);
Update (11.01.2013)
I just got a response back from Salesforce. It looks like they don't know how to implement 3.1.2 of the RFC which means that any query parameters you send in with the return_uri are not only ignored, but prohibited (at least when dynamic in nature). So, it looks like I can't use a library that works on every other platform and follows the standard--i have to create my own.
Sigh.

Twitter API upgrade for Windows Phone

I have tweet poster in my application which uses oAuth 1.0 which will retire soon and will be non functional. I have to upgrade my API to 1.1. Twitter development center says that, If oAuth is used by your application, you can easily transaction to 1.1 by only updating your API endpoint. What exactly is API endpoint?
Here I'm having hard understanding about API endpoint. I think my asyncronous post call URL must be upgraded.
Here is the relevant codes which I think that might include the answer;
private void btnPostTweet_Click(object sender, RoutedEventArgs e)
{
namebocx.Text = userScreenName;
if (txtBoxNewTweet.Text.Trim().Length == 0) { return; }
var credentials = new OAuthCredentials
{
Type = OAuthType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
ConsumerKey = TwitterSettings.consumerKey,
ConsumerSecret = TwitterSettings.consumerKeySecret,
Token = this.accessToken,
TokenSecret = this.accessTokenSecret,
Version = "1.0"
};
var restClient = new RestClient
{
Authority = TwitterSettings.StatusUpdateUrl,
HasElevatedPermissions = true,
Credentials = credentials,
Method = WebMethod.Post
};
restClient.AddHeader("Content-Type", "application/x-www-form-urlencoded");
// Create a Rest Request and fire it
var restRequest = new RestRequest
{
Path = "1/statuses/update.xml?status=" + txtBoxNewTweet.Text //Here must be endpoint of Api??
};
var ByteData = Encoding.UTF8.GetBytes(txtBoxNewTweet.Text);
restRequest.AddPostContent(ByteData);
restClient.BeginRequest(restRequest, new RestCallback(PostTweetRequestCallback));
}
}
and also here is the authentication settings:
public class TwitterSettings
{
public static string RequestTokenUri = "https://api.twitter.com/oauth/request_token";
public static string AuthorizeUri = "https://api.twitter.com/oauth/authorize";
public static string AccessTokenUri = "https://api.twitter.com/oauth/access_token";
public static string CallbackUri = "http://www.google.com";
public static string StatusUpdateUrl { get { return "http://api.twitter.com"; } }
public static string consumerKey = "myconsumerkeyhere";
public static string consumerKeySecret = "myconsumersecrethere";
public static string oAuthVersion = "1.0a";
}
Here what twitter says me to replace with this instead of written in my code;
https://api.twitter.com/1.1/statuses/update.json
and some parameters told here -->> https://dev.twitter.com/docs/api/1.1/post/statuses/update
How should I update my API endpoint, what kind of changes do I have to do?
If you can help me, I really appreciate
You can change this:
Path = "1/statuses/update.xml?status=" + txtBoxNewTweet.Text
//Here must be endpoint of Api??
to this:
Path = "1.1/statuses/update.json?status=" + txtBoxNewTweet.Text
//Here must be endpoint of Api??

Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407" via https

I try to connect to a server via https that requires authentication.Moreover, I have an http proxy in the middle that also requires authentication. I use ProxyAuthSecurityHandler to authenticate with the proxy and BasicAuthSecurityHandler to authenticate with the server.
Receiving java.io.IOException: Unable to tunnel through proxy.
Proxy returns "HTTP/1.1 407 Proxy Auth Required"
at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1525)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect (AbstractDelegateHttpsURLConnection.java:164)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at org.apache.wink.client.internal.handlers.HttpURLConnectionHandler.processRequest(HttpURLConnectionHandler.java:97)
I noticed that the implementation of ProxyAuthSecurityHandler is expecting response code 407 however, during debug we never get to the second part due to the IOException thrown.
Code snap:
ClientConfig configuration = new ClientConfig();
configuration.connectTimeout(timeout);
MyBasicAuthenticationSecurityHandler basicAuthProps = new MyBasicAuthenticationSecurityHandler();
basicAuthProps.setUserName(user);
basicAuthProps.setPassword(password);
configuration.handlers(basicAuthProps);
if ("true".equals(System.getProperty("setProxy"))) {
configuration.proxyHost(proxyHost);
if ((proxyPort != null) && !proxyPort.equals("")) {
configuration.proxyPort(Integer.parseInt(proxyPort));
}
MyProxyAuthSecurityHandler proxyAuthSecHandler =
new MyProxyAuthSecurityHandler();
proxyAuthSecHandler.setUserName(proxyUser);
proxyAuthSecHandler.setPassword(proxyPass);
configuration.handlers(proxyAuthSecHandler);
}
restClient = new RestClient(configuration);
// create the createResourceWithSessionCookies instance to interact with
Resource resource = getResource(loginUrl);
// Request body is empty
ClientResponse response = resource.post(null);
Tried using wink client versions 1.1.2 and also 1.2.1. the issue repeats in both.
What I found out is that when trying to pass through a proxy using https url we first send CONNECT and only then try to send the request. The proxy server cannot read any headrs we attach to the request, cause it doesn't have the key to decrypt the traffic.
This means that the CONNECT should already have the user/pass to the proxy to pass this stage.
here is a code snap I used - that works for me:
import sun.misc.BASE64Encoder;
import java.io.*;
import java.net.*;
public class ProxyPass {
public ProxyPass(String proxyHost, int proxyPort, final String userid, final String password, String url) {
try {
/* Create a HttpURLConnection Object and set the properties */
URL u = new URL(url);
Proxy proxy =
new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
HttpURLConnection uc = (HttpURLConnection)u.openConnection(proxy);
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType().equals(RequestorType.PROXY)) {
return new PasswordAuthentication(userid, password.toCharArray());
}
return super.getPasswordAuthentication();
}
});
uc.connect();
/* Print the content of the url to the console. */
showContent(uc);
} catch (IOException e) {
e.printStackTrace();
}
}
private void showContent(HttpURLConnection uc) throws IOException {
InputStream i = uc.getInputStream();
char c;
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
public static void main(String[] args) {
String proxyhost = "proxy host";
int proxyport = port;
String proxylogin = "proxy username";
String proxypass = "proxy password";
String url = "https://....";
new ProxyPass(proxyhost, proxyport, proxylogin, proxypass, url);
}
}
if you are using wink - like I do, you need to set the proxy in the ClientConfig and before passing it to the RestClient set the default authenticator.
ClientConfig configuration = new ClientConfig();
configuration.connectTimeout(timeout);
BasicAuthenticationSecurityHandler basicAuthProps = new BasicAuthenticationSecurityHandler();
basicAuthProps.setUserName(user);
basicAuthProps.setPassword(password);
configuration.handlers(basicAuthProps);
if (proxySet()) {
configuration.proxyHost(proxyHost);
if ((proxyPort != null) && !proxyPort.equals("")) {
configuration.proxyPort(Integer.parseInt(proxyPort));
}
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType().equals(RequestorType.PROXY)) {
return new PasswordAuthentication(proxyUser), proxyPass.toCharArray());
}
return super.getPasswordAuthentication();
}
});
}
restClient = new RestClient(configuration);
Resource resource = getResource(loginUrl);
// Request body is empty
ClientResponse response = resource.post(null);
if (response.getStatusCode() != Response.Status.OK.getStatusCode()) {
throw new RestClientException("Authentication failed for user " + user);
}
If Ilana Platonov's answer doesn't work, try editing the variables :
jdk.http.auth.tunneling.disabledSchemes
jdk.http.auth.proxying.disabledSchemes

WCF - how to create programatically custom binding with binary encoding over HTTP(S)

I'd like to convert my current HTTP/HTTPS WCF binding settings to use binary message encoding and I need to do it in code - not in XML configuration. AFAIK it's necessary to create CustomBinding object and set proper BindingElements, but I'm not able to figure out what elements should I use in my scenario.
Main points in my WCF configuration are:
use HTTP or HTTPS transport depending on configuration (in app.config)
use username message security
todo: add binary encoding instead of default text
My current code for setting the binding up (working, but without the binary encoding):
var isHttps = Settings.Default.wcfServiceBaseAddress.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase);
var binding = new WSHttpBinding(isHttps ? SecurityMode.TransportWithMessageCredential : SecurityMode.Message);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
I was trying this code, but it doesn't work - I don't know how to set message security element for username message security:
var custBinding = new CustomBinding();
custBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
//Transport Security (Not Required)
if (isHttps)
{
custBinding.Elements.Add(SecurityBindingElement.CreateUserNameForSslBindingElement());
}
//Transport (Required)
custBinding.Elements.Add(isHttps ?
new HttpsTransportBindingElement() :
new HttpTransportBindingElement());
Anybody knows how to set this up? I tried to search for similar problem/solution, but didn't succeeded...
I almost forgot this question, but here is my custom binding class which works with binary binding over HTTP with username+password validation and also allows to turn GZip compression on...
public class CustomHttpBinding: CustomBinding
{
private readonly bool useHttps;
private readonly bool useBinaryEncoding;
private readonly bool useCompression;
private readonly HttpTransportBindingElement transport;
public CustomHttpBinding(bool useHttps, bool binaryEncoding = true, bool compressMessages = false)
{
this.useHttps = useHttps;
transport = useHttps ? new HttpsTransportBindingElement() : new HttpTransportBindingElement();
useBinaryEncoding = binaryEncoding;
useCompression = compressMessages;
}
public long MaxMessageSize{set
{
transport.MaxReceivedMessageSize = value;
transport.MaxBufferSize = (int) value;
}}
public override BindingElementCollection CreateBindingElements()
{
BindingElement security;
if (useHttps)
{
security = SecurityBindingElement.CreateSecureConversationBindingElement(
SecurityBindingElement.CreateUserNameOverTransportBindingElement());
}
else
{
security = SecurityBindingElement.CreateSecureConversationBindingElement(
SecurityBindingElement.CreateUserNameForSslBindingElement(true));
}
MessageEncodingBindingElement encoding;
if (useCompression)
{
encoding = new GZipMessageEncodingBindingElement(useBinaryEncoding
? (MessageEncodingBindingElement)
new BinaryMessageEncodingBindingElement()
: new TextMessageEncodingBindingElement());
}
else
{
encoding = useBinaryEncoding
? (MessageEncodingBindingElement) new BinaryMessageEncodingBindingElement()
: new TextMessageEncodingBindingElement();
}
return new BindingElementCollection(new[]
{
security,
encoding,
transport,
});
}
}
The SecurityBindingElement has a AllowInsecureTransport property. If you set this to true you can use the HttpTransportBindingElement with message user name and password security.
Try SecurityBindingElement.CreateUserNameOverTransportBindingElement() instead:
var custBinding = new CustomBinding();
custBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
//Transport Security (Not Required)
if (isHttps)
{
custBinding.Elements.Add(SecurityBindingElement.CreateUserNameOverTransportBindingElement());
}
//Transport (Required)
custBinding.Elements.Add(isHttps ?
new HttpsTransportBindingElement() :
new HttpTransportBindingElement());