i create a wcf service and hosted it on windows azure. The wcf service is a https one. When ever i call the service the client needs a certificate to verify its authenticity.
When i type the service url on broswer it asks for a verifying certificate and the serivce runs.
So far so good.
Now i need to access the same service in an MVC 4 application. So i made a simple ajax call.
<script>
$(document).ready(function () {
$("#GetAdjustedSalary").click(function () {
var salary = parseFloat($("#salary").val());
var infalation = parseFloat($("#inflation").val());
$.ajax({
url: "https://newtonsheikh.cloudapp.net/SalaryService.svc/adjustedsalary?a=" + salary + "&b=" + infalation,
type: "GET",
dataType: "JSON",
contentType: "application/json",
success: function (data) {
alert(data);
}
});
});
});
</script>
But i dont get the result. Instead i always get abort error 403.
Do i need to write something on the web.config file in the MVC application? I am stuck and really need help out here.
Thanks
Got a solution:
In the ajax call i made a call to the controller
<script>
$(document).ready(function () {
$("#GetAdjustedSalary").click(function () {
var salary = parseFloat($("#salary").val());
var infalation = parseFloat($("#inflation").val());
var object = {
salary: salary,
infalation: infalation
}
var data = JSON.stringify(object);
$.ajax({
url: "Home/GetData/",
type: "POST",
data: data,
dataType: "JSON",
contentType: "application/json",
success: function (data) {
$("#answer").html(data);
}
});
});
});
Then in the controller:
[HttpPost]
public ActionResult GetData(string salary, string infalation)
{
string output = "";
try
{
X509Certificate Cert = X509Certificate.CreateFromCertFile("d://Cert//newton2.cer");
ServicePointManager.CertificatePolicy = new CertPolicy();
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://newtonsheikh.cloudapp.net/SalaryService.svc/adjustedsalary?a="+salary+" &b="+infalation+"");
Request.ClientCertificates.Add(Cert);
Request.UserAgent = "Client Cert Sample";
Request.Method = "GET";
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
Console.WriteLine("{0}" + Response.Headers);
Console.WriteLine();
StreamReader sr = new StreamReader(Response.GetResponseStream(), Encoding.Default);
int count;
char[] ReadBuf = new char[1024];
do
{
count = sr.Read(ReadBuf, 0, 1024);
if (0 != count)
{
output += new string(ReadBuf);
}
} while (count > 0);
}
catch (Exception ex)
{
//Throw the exception...lol :P
}
output = output.Replace("\0", "");
string jsonString = JsonConvert.SerializeObject(output, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return Json(jsonString, JsonRequestBehavior.AllowGet);
}
The CertPolicy Class:
class CertPolicy : ICertificatePolicy
{
public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem)
{
// You can do your own certificate checking.
// You can obtain the error values from WinError.h.
// Return true so that any certificate will work with this sample.
return true;
}
}
Related
I need to forward a HttpRequest made to an Azure function (through proxies.json) to a different endpoint. The request needs to be forwarded with query strings and headers intact. I need to modify the response body before sending it back to the original caller.
Proxies.json
"Transactions.BatchImport.Settlements": {
"matchCondition": {
"methods": [ "GET" ],
"route": "/transactions/v1/getsettlementsbyid/{batchId}"
},
"backendUri": "http://localhost/api/storebox/settlements/{batchId}"
},
Psudocode of desired functionality
[FunctionName(nameof(GetStoreboxSettlements))]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "GET", Route = "storebox/settlements/{batchId}")]
HttpRequest request, string batchId)
{
var response = ForwardRequest(request, $"www.anotherEndpoint.com/{batchId}");
response.Body = TransformBody(response.Body);
return new OkObjectResult(response);
}
Alternative solutions are welcome.
If anyone is interested, this is how I solved the problem:
Proxies.json
"Transactions.BatchImport.Settlements": {
"matchCondition": {
"methods": [ "GET" ],
"route": "/transactions/v1/getsettlementsbyid/{batchId}"
},
"backendUri": "http://localhost/api/v1/settlements/{batchId}"
},
Function code
[FunctionName(nameof(GetStoreboxSettlementsProxy))]
public async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "GET", Route = "v1/settlements/{batchId?}")]
HttpRequest request)
{
var baseUri = _environment.Get(Constants.Api.Endpoint);
var requestUri = new UriBuilder(baseUri)
{
Path = $"{request.Path}",
Query = request.QueryString.Value,
}.Uri;
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Headers.Authorization = AuthenticationHeaderValue.Parse(request.Headers["Authorization"]);
httpRequestMessage.RequestUri = requestUri;
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
try
{
response = await _httpClient.SendAsync(httpRequestMessage);
response.EnsureSuccessStatusCode();
var json = response.Content.ReadAsStringAsync().Result;
var storeBoxTransactionData = JsonConvert.DeserializeObject<StoreBoxTransactionData>(json);
if (storeBoxTransactionData.TotalSize > 0)
{
//Transform storebox settlement data
var transformedStoreBoxData = _processStoreBoxSettlementService.Process(storeBoxTransactionData);
response.Content = new StringContent(JsonConvert.SerializeObject(transformedStoreBoxData), Encoding.UTF8, "application/json");
return response;
}
}
catch (Exception e)
{
_logger.LogError($"Failed to get settlements {e}");
}
return response;
}
The code below, which is summarized for better understanding, works perfectly with LOCALHOST, however, when I put it in IIS, the body of the request always arrives EMPTY. Can someone help me?
Client application code:
login(userName: string, password: string): Observable<User> {
const headers = new HttpHeaders({
'Content-Type': 'application/json'
});
return this.http.post(`${environment.API_URL}/profiles/login`,
{ userName, password }, { headers }
).pipe(
tap((currentUser: User) => {
this.updateUser(currentUser)
.then(
() => {
console.log('currentUser login stored: ', AppSettings.currentUser);
},
error => console.error('Error storing currentUser login', error)
);
return AppSettings.currentUser;
}),
);
}
ASP.NET Core 3.1 application code on the server:
[Route("api/[controller]")]
[ApiController]
public class ProfilesController : ControllerBase
{
[HttpPost("login")]
public async Task<ActionResult> Login(LoginRequest request)
{
try
{
using (var Reader = new StreamReader(Request.Body, Encoding.UTF8))
{
var sb = new StringBuilder();
sb.AppendFormat("ContentType: {0}\n", Request.ContentType);
sb.AppendFormat("Request: {0}\n", Request.ToString());
sb.AppendFormat("ContentLength: {0}\n", Request.ContentLength.ToString());
if (Request.IsHttps)
sb.AppendFormat("{0}\n", "HTTPS!");
var headers = String.Empty;
foreach (var key in Request.Headers)
headers += key.Key + "=" + key.Value + Environment.NewLine;
sb.AppendFormat("Headers: \n{0}\n", headers);
sb.AppendFormat("QueryString: {0}\n", Request.QueryString);
var text = await Reader.ReadToEndAsync();
sb.AppendFormat("Body: {0}\n", text);
return Ok(sb.ToString());
}
return Ok("OK");
}
catch (System.Exception ex)
{
return Unauthorized($"{ex.Message}: {ex.StackTrace}");
}
}
}
Request result:
ContentType: application/json
Request: Microsoft.AspNetCore.Http.DefaultHttpRequest
ContentLength: 79
Headers:
Accept=*/*
Accept-Encoding=gzip, deflate, br
Cache-Control=no-cache
Connection=keep-alive
Content-Length=79
Content-Type=application/json
Host=loja.online
User-Agent=PostmanRuntime/7.22.0
Postman-Token=121f1927-c340-492f-a98b-0d6586ff32d8
QueryString:
Body:
Using POSTMAN the same thing happens!
Try Specifying the source:
public async Task<ActionResult> Login([FromBody] LoginRequest request) //Added [FromBody]
Just for Further Details
This is how my WCF service is defined to authenticate a user:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
string validateUser(string username, string password);
It simply returns "Validated" or "NotValidated" as result.
And my ExtJS code is:
function loginclick(btn) {
var form = mainPanel.getForm();
if (form.isValid()) {
var userget = Ext.getCmp('txtuser').value;
var passget = Ext.getCmp('txtpass').value;
var myparams = { 'username': userget, 'password': passget };
Ext.Ajax.request({
url: 'http://localhost:52984/ExtJsRestfulService.svc/validateUser',
params: Ext.encode(myparams),
method: 'POST',
headers: this.header || { 'Content-Type': 'application/json;charset=utf-8' },
success: function (response, options) {
var s = response.responseText;
Ext.MessageBox.alert('Success', s);
},
failure: function (response, options) {
Ext.MessageBox.alert('Failed', 'Unable to get');
}
});
}
}
When i click on the login button, I get bad request(400) error. My service is not in the same solution. When I post the data to an aspx form in the same solution it works. What am I doing wrong?
What about:
Ext.Ajax.request({
url: 'http://yourdomain:52984/ExtJsRestfulService.svc/validateUser?username='+userget+'&password='+passget,
params: Ext.encode(myparams),
method: 'GET',
headers: this.header || { 'Content-Type': 'application/json;charset=utf-8' },
success: function (response, options) {
var s = response.responseText;
Ext.MessageBox.alert('Success', s);
},
failure: function (response, options) {
Ext.MessageBox.alert('Failed', 'Unable to get');
}
});
Can you fetch the params from the url?
Have you tried without encoding?
try
params: {
'username': userget,
'password': passget
}
Why do you have two times the params config?
You shouldn't use Ext.getCmp instead use Ext.ComponentQuery.query('myXtype[itemId=myItemId]')[0]; http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.ComponentQuery
or
define the service in a manner that the call to it would be fullfilled like
string validateUser();
then inside the service do something similar to:
String pass = request.getParameter("password");
Like in java
I'm having some trouble with authenticating with ServiceStack using the BasicAuthProvider. All works well when I authenticate using the provider route 'auth/myauth' but when I go to one of my other service DTOS that use the [Authenticate] attribute e.g. /hello, I always get a 401 Unauthorized error even when I always supply the basic authentication details in the 'Authorization' header using beforeSend with jQuery.
Basically, I'm building an API for a mobile app that involves credential authentication on the first time(or if a supplied token isn't expired), then subsequently basic authentication of supplied token for other requests. I'm trying to authenticate every request, as described here. Also here. Here's my code:
Custom Provider
public class MyAuthProvider : BasicAuthProvider
{
public new static string Name = "MyAuth";
public new static string Realm = "/auth/myauth";
public MyAuthProvider()
{
this.Provider = Name;
this.AuthRealm = Realm;
}
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var httpReq = authService.RequestContext.Get<IHttpRequest>();
var basicAuth = httpReq.GetBasicAuthUserAndPassword();
if (basicAuth == null)
throw HttpError.Unauthorized("Invalid BasicAuth credentials");
var us = basicAuth.Value.Key;
var ps = basicAuth.Value.Value;
if (ps == "password")
{
return true;
}
return false;
}
}
Service
public class HelloService : Service
{
//handle OPTIONS in preflight - http://joeriks.com/2013/01/12/cors-basicauth-on-servicestack-with-custom-authentication/
public object Options(Hello request) { return true; }
[Authenticate("MyAuth")]
public object Post(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
[Authenticate("MyAuth")]
public object Get(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
Configure Method
public override void Configure(Container container)
{
Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
new MyAuthProvider()
}));
//register any dependencies your services use, e.g:
container.Register<ICacheClient>(new MemoryCacheClient() { FlushOnDispose = false });
//set endpoint information
SetConfig(new EndpointHostConfig
{
GlobalResponseHeaders =
{
{"Access-Control-Allow-Origin","http://localhost"},
{"Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"},
{"Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Origin" }
},
});
}
This works
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return "Basic " + hash;
}
////
$.ajax({
url: 'http://localhost:61750/auth/myauth?format=json',
type: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", make_base_auth("id#email.com","password"));
}
}).done(function (data) {
if( console && console.log ) {
console.log("Sample of data:", data);
}
});
But this doesn't
$.ajax({
url: 'http://localhost:61750/hello?format=json',
data: { Name:"Foo" },
type: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", make_base_auth("id#email","password"));
}
}).done(function (data) {
if( console && console.log ) {
console.log("Sample of data:", data);
}
});
Thanks for your help.
I had to create a custom authenticate attribute with guidance from this gist -> https://gist.github.com/joeriks/4518393
In the AuthenticateIfBasicAuth method, I set provider to use MyAuthProvider.Name
Then,
[CustomAuthenticate]
public object Post(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
I have an ajax enabled WCF service method :
[OperationContract]
public string Test(string name)
{ return "testing testing." + name; }
and I am calling it with following code:
$(document).ready(function () {
var varData = $("#NewSkill").val();
$("#Button1").click(function () {
$.ajax({
type: "POST",
url: "TimeService.svc/Test",
data: '{"name" : "John"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg.d);
}
});
});
});
I want to call this method continuously after every 5 seconds using above code . How can I do this ?
Move the $.ajax(); part to a Javascript function say AjaxCall(). Create a javascript variable
var isActivated = false;
$(document).ready(function () {
while(isActivated){
setTimeout("AjaxCall()",3000);
}
}
);
$("#Button1").click(isActivated = true)
Hope this helsps...