Sending credentials in url is not supported in chrome 59 - google-chrome

I have a basic authentication for a SSRS report server, to avoid the login pop up window while hitting a SSRS report server from a web server. I'm sending the credentials in url itself. It was working upto google chrome 58, but now it is updated to chrome 59. Now i'm not able to send credentials in the browser url.
Example https://gooduser:secretpassword#www.example.co
username : gooduser
password : secredpassword
Kindly help on this please!

I solve the same problem with chrome extension.
In extension background.js
chrome.extension.onMessage.addListener( function(request, sender, sendResponse){
chrome.webRequest.onAuthRequired.addListener(
function(details, callbackFn) {
console.log("onAuthRequired!", details, callbackFn);
callbackFn({
authCredentials: {username: request.username, password: request.password }
});
},
{urls: request.url + "/*"]},
['asyncBlocking']
);
});
in extension contentscript.js
window.addEventListener("message", function(event) {
if ( event.type == "BASIC_AUTH" ) {
chrome.runtime.sendMessage(
event.data,
event.data.sender,
function (response) {}
);
}
});
in HTML javascript
window.postMessage({ type: "BASIC_AUTH", url:"www.mydomain.com", username:"myusername", password:"mypassword" }, "*");
If you like use extensions from Chrome Web Store like : MultiPass for HTTP basic authentication

You can use the "MultiPass for HTTP basic authentication" Chrome Extension to handle this.
You can do via GitHub MultiPass for HTTP basic authentication
(or)
Download the extension from Chrome Web Store - MultiPass Chrome Extension
(Or)
Download the extension as crx. You can get it as crx from chrome-extension-downloader
Once you download the Extension as crx File - Configuring the same into your Test/Source is very simple.
And this can be tested using the Sample Basic Auth-Site.
public class ChromeAuthTest {
WebDriver driver;
public ChromeAuthTest() {
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
}
private void initDriver() {
ChromeOptions cOptions = new ChromeOptions();
cOptions.addExtensions(new File("MultiPass-for-HTTP-basic-authentication_v.crx"));
driver = new ChromeDriver(cOptions);
configureAuth(
"https://the-internet.herokuapp.com/basic_auth",
"admin",
"admin");
}
private void configureAuth(String url, String username, String password) {
driver.get("chrome-extension://enhldmjbphoeibbpdhmjkchohnidgnah/options.html");
driver.findElement(By.id("url")).sendKeys(url);
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.className("credential-form-submit")).click();
}
public void doTest() {
initDriver();
driver.get("https://the-internet.herokuapp.com/basic_auth");
System.out.println(driver.getTitle());
driver.quit();
}
public static void main(String[] args) {
new ChromeAuthTest().doTest();
}
}
NOTE: This is taken from this Answer.
Hope this helps!

Related

Multiple native app are ran by connecting with native messaging when reload the extension

In chrome extension, I use native messaging to call the local application. But I found an issue that everytime I reload the extension, it seems like a new process is created for the application. By the documentation, the app will be ended if the port is disconnected or the page is closed. Does that mean reload extension won't close the background page? How can I solve this problem? Also, I cannot find my local application process in the chrome task manager.
// background.js
var port = null;
connectToNativeHost();
// Receive message from other js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("background recieved message from " + sender.url + JSON.stringify(request));
parseMessage(request);
}
);
//onNativeDisconnect
function onDisconnected()
{
console.log(chrome.runtime.lastError);
console.log('disconnected from native app.');
port = null;
}
// Receive message from native app
function onNativeMessage(message)
{
console.log('recieved message from native app: ' + JSON.stringify(message));
}
//connect to native host and get the communicatetion port
function connectToNativeHost()
{
var nativeHostName = 'com.group_project.time_tracker';
port = chrome.runtime.connectNative(nativeHostName);
port.onMessage.addListener(onNativeMessage);
port.onDisconnect.addListener(onDisconnected);
console.log("connected");
}
// Send message to native app
function sendMessage(message)
{
port.postMessage(message);
console.log('send messsage to native app: ' + JSON.stringify(message));
}

Passing data to SignalR Hub using Post method to Web Api returned: The remote server returned an error: (404) Not Found

Recently, I just started to learn on SignalR and I had been testing on one project that I found on GitHub. However I did stuck when trying to Post data to Web api part.
I just get everything done yet I cannot really make this project to work somehow. This is basically the program for the project. It is a console app and did send the data(Json) to Web Api
// Get the stuff we need to send
GetMetrics(out cpuTime, out memUsage, out totalMemory);
// Send the data
var postData = new
{
MachineName = System.Environment.MachineName,
Processor = cpuTime,
MemUsage = memUsage,
TotalMemory = totalMemory
};
var json = JsonConvert.SerializeObject(postData);
// Post the data to the server http://localhost:80/api/cpuinfo
var serverUrl = new Uri(ConfigurationManager.AppSettings["ServerUrl"]);
var client = new WebClient();
client.Headers.Add("Content-Type", "application/json");
client.UploadString(serverUrl, json);
Moving to web part. I did have the Asp.net MVC and did create the RouteConfig inside the App_Start to route HTTP request to controller.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
And this is the controller class.
public class CpuInfoController : ApiController
{
public void Post(CpuInfoPostData cpuInfo)
{
var context = GlobalHost.ConnectionManager.GetHubContext<CpuInfo>();
context.Clients.All.cpuInfoMessage(cpuInfo.MachineName, cpuInfo.Processor, cpuInfo.MemUsage, cpuInfo.TotalMemory);
}
}
I also had it registered inside Global.asax as below
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
After done all this, I still cant get this done and my console application pop up some errors as in the image here. It seems like the api/cpuinfo was not found.
Please advice me if anything that I had done wrong here.
The full version of this project can be found here.
You have to modify the File App.config in "CpuInfoClient" project. (the value of the Key)
Use "http" instead of "https"
Change the port number to the actual port number (instead of 44300), that uses the web application after starting. The exact port for the substitution you can see , when the web app starts in IE or Firefox. The port is also in "WcfCpuApp -> Properties -> Web -> Project-URL
Be sure that your web application is running, when you start "CpuInfoClient"

Serilog / JSNLog .NET Core logging empty JSON

I have a .NET Core project using Serilog and JSNLog for client side logging. If I pass a JSON object from the client to the server and log it using Serilog, the logged JSON object is empty.
The very weird thing is that, if I have the debugger attached, the JSON is logged fine.
For example:
While debugging I get:
[11:00:01 FTL] this works
[11:00:02 INF] Request finished in 342.1967ms 200 text/plain
[11:00:02 FTL] "testMessage": "this is an error"
[11:00:02 INF] Request finished in 374.7837ms 200 text/plain
When Crtl+F5 I get:
[10:59:14 FTL] this works
[10:59:14 INF] Request finished in 253.3403ms 200 text/plain
[10:59:15 FTL] [[[]]]
[10:59:15 INF] Request finished in 267.2553ms 200 text/plain
I'm not sure if the problem is with Serilog or JSNLog, but any help would be appreciated.
I've made a very simple sample app to replicate this. Using the default .NET Core Webapp
Dependencies are as shown:
in Startup.cs:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
Log.Logger = new LoggerConfiguration()
.WriteTo.Console().CreateLogger();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddSerilog();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseJSNLog(new LoggingAdapter(loggerFactory));
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
And in my front end:
<script src="~/lib/jsnlog.js/jsnlog.min.js"></script>
<script>
JL().fatal({ testMessage: "this is an error" });
JL().fatal("this works");
</script>
I had a similar issue. I took a look at JSNLog and what seemed to be the issue was the logging of the JSON .NET object that was being created when desearializing an object from the log message.
I did the following workaround:
I installed the Nuget package Destructurama.JsonNet (Install-Package Destructurama.JsonNet)
Then I changed the Logger configuration to include the destructuring:
Log.Logger = new LoggerConfiguration()
.Destructure.JsonNetTypes()
.WriteTo.Console()
.CreateLogger();
I then created a CustomLoggingAdapter class like this:
public class CustomLoggingAdapter: ILoggingAdapter
{
private ILoggerFactory _loggerFactory;
public CustomLoggingAdapter(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public void Log(FinalLogData finalLogData)
{
ILogger logger = _loggerFactory.CreateLogger(finalLogData.FinalLogger);
Object message = LogMessageHelpers.DeserializeIfPossible(finalLogData.FinalMessage);
switch (finalLogData.FinalLevel)
{
case Level.TRACE: logger.LogTrace("{#logMessage}", message); break;
case Level.DEBUG: logger.LogDebug("{#logMessage}", message); break;
case Level.INFO: logger.LogInformation("{#logMessage}", message); break;
case Level.WARN: logger.LogWarning("{#logMessage}", message); break;
case Level.ERROR: logger.LogError("{#logMessage}", message); break;
case Level.FATAL: logger.LogCritical("{#logMessage}", message); break;
}
}
}
and changed the log to have the following format {#logMessage}
Note: LogMessageHelpers.DeserializeIfPossible can be found in the JSONLog GitHub repo
Then I changed the JSNLog configuration to take in my CustomLoggingAdapter like this:
app.UseJSNLog(new CustomLoggingAdapter(loggerFactory), jsnlogConfiguration);
and the log messages appeared.
Let me know if that helps

Login to Chrome extension with a Google user other than the one in use by Chrome

I have a Chrome extension that requests a user to login using the chrome.identity.getAuthToken route. This works fine, but when you login you can only use the users that you have accounts in Chrome for.
The client would like to be able to login with a different Google account; so rather than using the.client#gmail.com, which is the account Chrome is signed in to, they want to be able to login using the.client#company.com, which is also a valid Google account.
It is possible for me to be logged in to Chrome with one account, and Gmail with a second account, and I do not get the option to choose in the extension.
Is this possible?
Instead of authenticating the user using the chrome.identity.getAuthToken , just implement the OAuth part yourself.
You can use libraries to help you, but the last time I tried the most helpful library (the Google API Client) will not work on a Chrome extension.
Check out the Google OpenID Connect documentation for more info. In the end all you have to do is redirect the user to the OAuth URL, use your extension to get Google's answer (the authorization code) and then convert the authorization code to an access token (it's a simple POST call).
Since for a Chrome extension you cannot redirect to a web server, you can use the installed app redirect URI : urn:ietf:wg:oauth:2.0:oob. With this Google will display a page containing the authorization code.
Just use your extension to inject some javascript code in this page to get the authorization code, close the HTML page, perform the POST call to obtain the user's email.
Based on David's answer, I found out that chrome.identity (as well as generic browser.identity) API now provides a chrome.identity.launchWebAuthFlow method which can be used to launch an OAuth workflow. Following is a sample class showing how to use it:
class OAuth {
constructor(clientId) {
this.tokens = [];
this.redirectUrl = chrome.identity.getRedirectURL();
this.clientId = clientId;
this.scopes = [
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.send"
];
this.validationBaseUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo";
}
generateAuthUrl(email) {
const params = {
client_id: this.clientId,
response_type: 'token',
redirect_uri: encodeURIComponent(this.redirectUrl),
scope: encodeURIComponent(this.scopes.join(' ')),
login_hint: email
};
let url = 'https://accounts.google.com/o/oauth2/auth?';
for (const p in params) {
url += `${p}=${params[p]}&`;
}
return url;
}
extractAccessToken(redirectUri) {
let m = redirectUri.match(/[#?](.*)/);
if (!m || m.length < 1)
return null;
let params = new URLSearchParams(m[1].split("#")[0]);
return params.get("access_token");
}
/**
Validate the token contained in redirectURL.
This follows essentially the process here:
https://developers.google.com/identity/protocols/OAuth2UserAgent#tokeninfo-validation
- make a GET request to the validation URL, including the access token
- if the response is 200, and contains an "aud" property, and that property
matches the clientID, then the response is valid
- otherwise it is not valid
Note that the Google page talks about an "audience" property, but in fact
it seems to be "aud".
*/
validate(redirectURL) {
const accessToken = this.extractAccessToken(redirectURL);
if (!accessToken) {
throw "Authorization failure";
}
const validationURL = `${this.validationBaseUrl}?access_token=${accessToken}`;
const validationRequest = new Request(validationURL, {
method: "GET"
});
function checkResponse(response) {
return new Promise((resolve, reject) => {
if (response.status != 200) {
reject("Token validation error");
}
response.json().then((json) => {
if (json.aud && (json.aud === this.clientId)) {
resolve(accessToken);
} else {
reject("Token validation error");
}
});
});
}
return fetch(validationRequest).then(checkResponse.bind(this));
}
/**
Authenticate and authorize using browser.identity.launchWebAuthFlow().
If successful, this resolves with a redirectURL string that contains
an access token.
*/
authorize(email) {
const that = this;
return new Promise((resolve, reject) => {
chrome.identity.launchWebAuthFlow({
interactive: true,
url: that.generateAuthUrl(email)
}, function(responseUrl) {
resolve(responseUrl);
});
});
}
getAccessToken(email) {
if (!this.tokens[email]) {
const token = await this.authorize(email).then(this.validate.bind(this));
this.tokens[email] = token;
}
return this.tokens[email];
}
}
DISCLAIMER: above class is based on open-source sample code from Mozilla Developer Network.
Usage:
const clientId = "YOUR-CLIENT-ID"; // follow link below to see how to get client id
const oauth = new OAuth();
const token = await oauth.getAccessToken("sample#gmail.com");
Of course, you need to handle the expiration of tokens yourself i.e. when you get 401 from Google's API, remove token and try to authorize again.
A complete sample extension using Google's OAuth can be found here.

Telerik Html5 Report Viewer "The requested resource does not support http method 'GET' "

I am getting this while using html5 report viewer in my MVC project
Unable to get report parameters:
Report 'Application.Reports.Report1, WebAppUsingTelerikReport' cannot be resolved.
After clicking the error in console it says The requested resource does not support http method 'GET'
My ReportsController
public class ReportsController : ReportsControllerBase
{
protected override IReportResolver CreateReportResolver()
{
var appPath = HttpContext.Current.Server.MapPath("~/Reports");
//var reportsPath = Path.Combine(appPath, #"..\..\..\Report Designer\Examples");
return new ReportFileResolver(appPath)
.AddFallbackResolver(new ReportTypeResolver());
}
[System.Web.Http.HttpPost]
protected override ICache CreateCache()
{
return Telerik.Reporting.Services.Engine.CacheFactory.CreateFileCache();
}
}
View
#{
Layout = null;
var typeReportSource = new TypeReportSource() { TypeName = "Application.Reports.Report1, WebAppUsingTelerikReport"
};
}
<script type="text/javascript">
$(document).ready(function () {
debugger;
$("#reportViewer1")
.telerik_ReportViewer({
serviceUrl: "/api/reports/",
templateUrl: '../ReportViewer/templates/telerikReportViewerTemplate-8.2.14.1027.html',
reportSource: {
report: "#typeReportSource",
},
viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
scaleMode: telerikReportViewer.ScaleModes.FIT_PAGE_WIDTH,
scale: 1.0,
ready: function () {
}
});
});
</script>
It sounds like a resource is being requested which you have specified not to accept HTTP GET requests. I would expect based on your code that the HTML5 Report Viewer is attempting to call CreateCache() but you have specified it should only accept HTTP POST requests with [System.Web.Http.HttpPost]. If this isn't the issue check if there is another Controller method which is restricted from processing GET requests.
Using a debugger on the server side or in-browser network profiler on the client side it should be easy to identify which requested resource is causing the issue.