webflux: cross Domain + basic authorization is not working? - spring-webflux

i used Spring 2.0.1, here is my SecurityWebFilterChain
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
// Demonstrate that method security works
// Best practice to use both for defense in depth
.authorizeExchange()
.anyExchange().permitAll()
.and()
.httpBasic().and()
.build();
Here is Cros config
#Configuration
#EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
final String ALLOWED_HEADERS = "x-requested-with, authorization,
Content-Type, Authorization, credential, X-XSRF-TOKEN";
final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
final String ALLOWED_ORIGIN = "http://192.168.18.124:8888";
final long MAX_AGE = 3600;
registry.addMapping("/report/**")
.allowedOrigins(ALLOWED_ORIGIN)
.allowedMethods("PUT", "GET")
.allowedHeaders("x-requested-with", "authorization",
"Content-Type", "Authorization", "credential", "X-XSRF-TOKEN")
.allowCredentials(true).maxAge(3600);
}
}
My ajax code
var data = {};
$.ajax({
type: 'GET',
async: false,
url: 'http://192.168.18.135:8765/report/summaries/date/2017-06-12',
dataType: 'json',
data: data,
crossDomain: true,
crossOrigin: true,
beforeSend: function (xhr) {
xhr.withCredentials = true;
xhr.setRequestHeader('Authorization', 'Basic ' + "xxxxx");
},
success: function (responseData) {
console.log('-----------------response-------------------');
console.log(responseData);
console.log('-----------------response-------------------');
response = responseData;
},
error: function (responseData) {
response.error = responseData;
}
});
return response;
});
the error responded from server:
http://192.168.18.135:8765/report/summaries/date/2017-06-12. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.18.124:8888' is therefore not allowed access. The response had HTTP status code 500.
if i remove
xhr.setRequestHeader('Authorization', 'Basic ' + "xxxxx");
it will return 401 authorization.
Is is possible cros domain + basic authorization?

This is my CORS configuration. Create a new Class WebConfig and declare a Bean like this:
#Configuration
public class WebConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
};
}
}

Related

POST command missing parameters in SSL (https:) but working with http

I have an ASMX web service for login into the website.
I call the web service by using an ajax request.
this works as intended on non-SSL (HTTP). However, when running in SSL (https)
I got an error message as below.
{"Message": "Invalid web service call, missing value for parameter: 'username'.",
"StackTrace": "
at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)
at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary`2 parameters)
at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)
at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType": "System.InvalidOperationException"
}
Here is my ASMX web service.
using System.Web.Security;
using System.Web.Services;
namespace MyWebSite
{
[WebService(Namespace = "https://mywebsite.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class AuthService : System.Web.Services.WebService
{
[WebMethod]
public bool Login(string username, string password)
{
if (Membership.ValidateUser(username, password)){
FormsAuthentication.SetAuthCookie(username, true);
return true;
}
else {
return false;
}
}
}
}
And this is the ajax for call the web service.
function login(event) {
if ($('#form1').validate().form()) {
$.ajax({
type: 'POST',
url: 'Services/AuthService.asmx/Login',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({
username: $('#inputUsername').val(),
password: $('#inputPassword').val()
}),
success: function (response) {
$('#btn-login').removeAttr('disabled');
//
if (response.d) {
window.location.href = 'default.aspx';
}
},
error: function (response) {
var err = $.parseJSON(response.responseText);
console.log(err.message);
}
});
}
}
Please help me. Thanks in advance!

ASP.NET Core 3.1 is getting an empty body

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

Sending data to Restful WCF service using ExtJS

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

401 error when using [Authenticate] with BasicAuthProvider

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 };
}

Call a HTTPS WCF Service with Certificate authentication

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;
}
}