I'm trying to send a request to an API in soap using WCF, in the API documentation I was told that first I need to pass the following authentication header containing a fixed token:
<soapenv:Header>
<Token xmlns="Token">12345as566788ds900987654</Token>
</soapenv:Header>
After passing and validating this token I access the class I need to send the file, I tried with the code below that I managed to assemble searching, but I'm getting the error: System.ServiceModel.FaultException: informing that I need to pass the token tag in the header.
Below how I'm trying to do it:
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new();
requestMessage.Headers["Token"] = "12345as566788ds900987654";
var result= client.uploadFile(file);
}
You can try this for the client-side:
IContextChannel contextChannel = (IContextChannel)myServiceProxy;
using (OperationContextScope scope = new OperationContextScope(contextChannel))
{
MessageHeader header = MessageHeader.CreateHeader("PlayerId", "", _playerId);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
act(service);
}
And you can try this on the server-side:
private long ExtractPlayerIdFromHeader()
{
try
{
var opContext = OperationContext.Current;
var requestContext = opContext.RequestContext;
var headers = requestContext.RequestMessage.Headers;
int headerIndex = headers.FindHeader("PlayerId", "");
long playerId = headers.GetHeader<long>(headerIndex);
return playerId;
}
catch (Exception ex)
{
this.Log.Error("Exception thrown when extracting the player id from the header", ex);
throw;
}
}
Related
I have a set of endpoints developed in the KSOAP format in Asp.net. The website has a login form which takes Email id and pass in order to log user in. Now the behavior of the website is that, it saves the Email id in the local storage as key and the website uses the same session to retrieve feedback received on that Email and feedback inserted by that Email id. Now on the Android Native side, When request to log in it logs in successfully though return null when retrieve feedback is called as it might be initiating a new session. Thus I am just getting a null object as there is no Email key stored in the local storage. Please help me in order to maintain same session and after login I can request other relevant endpoints.
I have tried using the same Envelop object, using it both the both http requests, also tried to save header but nothing worked.
For Logging In
public class LoginWebservice {
//Namespace of the Webservice - can be found in WSDL
private static String NAMESPACE = "http://tempuri.org/";
//Webservice URL - WSDL File location
private static String URL = "https://www.xxxxxx/feedback/Webservice1.asmx?WSDL";
//SOAP Action URI again Namespace + Web method name
private static String SOAP_ACTION = "http://tempuri.org/";
public static boolean invokeLoginWS(String userName,String passWord, String webMethName) {
boolean loginStatus = false;
// Create request
SoapObject request = new SoapObject(NAMESPACE, webMethName);
// Property which holds input parameters
PropertyInfo unamePI = new PropertyInfo();
PropertyInfo passPI = new PropertyInfo();
// Set Username
unamePI.setName("Email");
// Set Value
unamePI.setValue(userName);
// Set dataType
unamePI.setType(String.class);
// Add the property to request object
request.addProperty(unamePI);
//Set Password
passPI.setName("Password");
//Set dataType
passPI.setValue(passWord);
//Set dataType
passPI.setType(String.class);
//Add the property to request object
request.addProperty(passPI);
// Create envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
// Set output SOAP object
envelope.setOutputSoapObject(request);
// Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
// Invoke web service
androidHttpTransport.call(SOAP_ACTION+webMethName, envelope);
// Get the response
SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
// Assign it to boolean variable variable
loginStatus = Boolean.parseBoolean(response.toString());
Log.w("LoginStatuslog",Boolean.toString(loginStatus));
} catch (Exception e) {
//Assign Error Status true in static variable 'errored'
// CheckDNLoginActivity.errored = true;
e.printStackTrace();
}
//Return booleam to calling object
return loginStatus;
}
-----------------------------------------------------------------------
For retrieving relevant Feedbacks
public static String invokeJSONWS(String methName) {
// Create request
SoapObject request = new SoapObject(NAMESPACE,methName);
// Property which holds input parameters
/* PropertyInfo paramPI = new PropertyInfo();
// Set Name
// Set dataType
paramPI.setType(String.class);
// Add the property to request object
request.addProperty(paramPI);*/
// Create envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
// Set output SOAP object
envelope.setOutputSoapObject(request);
envelope.headerOut = new Element[1];
envelope.headerOut[0] = LoginWebservice.buildAuthHeader();
// Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
// Invole web service
androidHttpTransport.call(SOAP_ACTION+methName, envelope);
// Get the response
SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
Log.e("Soap Res",response.toString());
// Assign it to static variable
responseJSON = response.toString();
JSONArray json = new JSONArray(responseJSON);
Log.d("Response", json.toString());
} catch (Exception e) {
e.printStackTrace();
}
return responseJSON;
}
It returns a Null object
I'm migrating from .NET Core 1.1 to 2.0, and now I have to update my Authentication too.
I'm using OAuth and OpenIddict to .NET Core 2.0
When I'm sending the request to my connect/token I'm getting this:
OpenIddict.Server.OpenIddictServerHandler[0] The token response was
successfully returned: {
"error": "unsupported_grant_type",
"error_description": "The specified 'grant_type' parameter is not
supported."
}.
This is my request method:
using (var client = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, $"{url}/connect/token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = clientId,
["client_secret"] = clientSecret,
["pessoaid"] = pessoaId,
["usuarioid"] = usuarioId,
["conta"] = conta,
["cpfcnpj"] = userDoubleCpf,
["fonteDados"] = fonteDados,
["userIdsLogged"] = userIdsLogged
});
var response = await client.SendAsync(request, HttpCompletionOption.ResponseContentRead);
response.EnsureSuccessStatusCode();
var result = JObject.Parse(await response.Content.ReadAsStringAsync());
if (result["error"] != null)
{
throw new InvalidOperationException("An error occurred while retrieving an access token.");
}
return result;
}
My OpenIddictApplications is generated when an application is linked to the user account, so the ClientId and Secret is generated, when a login request is send to my API and retrieve the respective values.
I have folowed the oppeniddict documentation and I have included everything in my Startup.cs
This is my AuthorizationController:
[HttpPost("~/connect/token"), Produces("application/json")]
public async Task<IActionResult> Exchange(OpenIdConnectRequest request)
{
Debug.Assert(request.IsTokenRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. " +
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
if (request.IsClientCredentialsGrantType())
{
// Note: the client credentials are automatically validated by OpenIddict:
// if client_id or client_secret are invalid, this action won't be invoked.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);
if (application == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidClient,
ErrorDescription = "The client application was not found in the database."
});
}
// Create a new authentication ticket.
var ticket = CreateTicket(request, application);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
ErrorDescription = "The specified grant type is not supported."
});
}
I'm generating the AuthenticationTicket and returning this.
Any idea about what might be causing this kind of badrequest when I try to send the request to take my token?
This happens because you do not configure the client credentials flow on you Startup.cs.
See the example: https://github.com/openiddict/openiddict-samples/blob/dev/samples/ClientCredentialsFlow/AuthorizationServer/Startup.cs
Attention for line 52:
// Enable the client credentials flow.
options.AllowClientCredentialsFlow();
I'm playing with OneDrive SDK 1.1.15.0:
try
{
AppConfig appConfig = new AppConfig
{
MicrosoftAccountAppId = oneDriveClientID, //something like 00000000123456AB
MicrosoftAccountClientSecret = oneDriveClientSecret, //something like 3vx[...]1sJ
MicrosoftAccountReturnUrl = "https://localhost/return",
MicrosoftAccountScopes = new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
};
OneDriveClient oneDriveClient = new OneDriveClient(appConfig);
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
//more code
await oneDriveClient.SignOutAsync();
}
catch (Exception ex)
{
throw ex;
}
My problem is in line:
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
that throws the following exception:
Microsoft.OneDrive.Sdk.OneDriveException, AuthenticationFailure: Failed to retrieve a valid authentication token for the user.
Any ideas?
Thank you in advance!
UPDATE
After reading comment from ginach (thank you!), I update my code. Some arguments to underline:
I want to access OneDrive from an Azure worker Role, so no authentication windows or something like that.
I upload the Microsoft.OneDrive SDK to 1.1.20 version.
I already registered my application to the OneDrive dev portal.
My actual code is:
try
{
MicrosoftAccountServiceInfo serviceInfo = new MicrosoftAccountServiceInfo();
serviceInfo.AppId = oneDriveClientID; //something like: 00000000ABCDEFGH
serviceInfo.ClientSecret = oneDriveClientSecret; //something like: 3vx[...]1sJ
serviceInfo.ReturnUrl = oneDriveReturnUrl; //something like: https://localhost/return
serviceInfo.Scopes = oneDriveAccountScopes; //something like new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
MicrosoftAccountAuthenticationProvider authenticationProvider = new MicrosoftAccountAuthenticationProvider(serviceInfo);
OneDriveClient oneDriveClient = await OneDriveClient.GetAuthenticatedMicrosoftAccountClient(oneDriveClientID, oneDriveReturnUrl, oneDriveAccountScopes, authenticationProvider);
//more code
await oneDriveClient.SignOutAsync();
}
catch (OneDriveException odex)
{
throw odex;
}
catch (Exception ex)
{
throw ex;
}
I obtain again and again (in OneDriveClient.GetAuthenticatedMicrosoftAccountClient method) a OneDriveException stating (Error property): AuthenticationFailure - Failed to retrieve a valid authentication token for the user.
Any suggestion?
Thank you.
UPDATE 2
OK, I'm trying a new approach. Using RestSharp I try to login to OneDrive with that code:
string clientId = "00[...]00";
string scopes = "wl.signin, wl.offline_access, onedrive.readonly";
string responseType = "code";
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
RestClient client = new RestClient("https://login.live.com");
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.Resource = "oauth20_authorize.srf";
request.AddQueryParameter("client_id", clientId);
request.AddQueryParameter("scope", scopes);
request.AddQueryParameter("response_type", responseType);
request.AddQueryParameter("redirect_uri", redirectUri);
IRestResponse response = client.Execute(request);
string content = response.Content;
I check the request with Fiddler and what I'm sending is:
https://login.live.com/oauth20_authorize.srf?client_id=00[...]00&scope=wl.signin%20wl.offline_access%20onedrive.readonly&response_type=code&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf
But OneDrive server answers my with:
Microsoft account requires JavaScript to sign in. This web browser either does not support JavaScript, or scripts are being blocked. To find out whether your browser supports JavaScript, or to allow scripts, see the browser's online help.
So I try the request in a browser and OneDrive server redirects me to the authorization page:
Now the question is: is there any workaround to skip the manual authorization?
Thank you,
Attilio
The client requires an authentication provider to be able to retrieve authentication tokens. There are a few ways to do this depending on your current platform.
Create your own IAuthenticationProvider implementation. The authentication provider is responsible for setting the Authentication header on requests. Here's how you would create a client instance with a custom authentication provider:
var client = new OneDriveClient(appConfig, serviceInfoProvider: new
ServiceInfoProvider(new CustomAuthenticationProvider()));
Use one of the various default authentication implementations. Take a look at the SDK authentication documentation for the available options and examples.
If you have a refresh token and only want to do the silent authentication flow you can use OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient. Here's an example:
var client = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(clientId, returnUrl, scopes, refreshToken);
I am working on Windows Broker Authentication.I can successfully authenticate in to the calling app and can comeback to the home page after authentication.
I am not able to get the user info (username) .I have tried but I get one message as written below.
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
WinRT information: Response status code does not indicate success: 401 (Unauthorized).
Additional information: Unauthorized (401).
Response status code does not indicate success: 401 (Unauthorized).
If there is a handler for this exception, the program may be safely continued.
I have written my code below.Please friends help me.
private const string RESOURCE_NAME ="id_token";
public async Task<UserInfo> GetName(string accessToken)
{
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new Windows.Web.Http.Headers.HttpCredentialsHeaderValue("OAuth", accessToken);
var result = await client.GetStringAsync(new Uri(loginUri));
var profileInformation =JsonObject.Parse(result).GetObject();
var name = profileInformation.GetNamedString("username");
return new UserInfo { Name = name };
}
catch (JsonException ex)
{
throw new JsonException(ex.message);
}
}
private async void btnHomeLogin_Click(object sender, RoutedEventArgs e)
{
string Scope = "openid profile";
var client = new OAuth2Client(new Uri(loginUri));
var startUri = client.CreateAuthorizeUrl(
ClientID,
RESOURCE_NAME,
Scope,
RedirectURI,
state,
nonce);
string Authresult;
try
{
var webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, new Uri(startUri),new Uri(RedirectURI));
switch (webAuthenticationResult.ResponseStatus)
{
case Windows.Security.Authentication.Web.WebAuthenticationStatus.Success:
//Successful authentication.
Authresult = webAuthenticationResult.ResponseData.ToString();
UserInfo userInfo = await GetName(RESOURCE_NAME);
break;
case Windows.Security.Authentication.Web.WebAuthenticationStatus.ErrorHttp:
//HTTP error.
Authresult = webAuthenticationResult.ResponseErrorDetail.ToString();
break;
default:
//Other error.
Authresult = webAuthenticationResult.ResponseData.ToString();
break;
}
}
catch (Exception ex)
{
//Authentication failed. Handle parameter, SSL/TLS, and Network Unavailable errors here.
Authresult = ex.Message;
}
}
If you are exactly using the above code, then based on the above, you are calling GetName function with a constant string (RESOURCE_NAME) instead of the actual AuthResult (accessToken) that was returned from the webAuthenticationResult. If the intention of calling the WebAuthenticationBroker is to get back an Access Token which should later be used with HttpClient, then you need to adjust your code accordingly and make use of the right access Token when calling the HttpClient code. Otherwise the 401 is not unexpected if you are not passing the right token.
I'm using DotNetOpenAuth's OAuth2 library to handle authorization with another third party system. It all works great, except that the third party system is returning the UserId="testname" in the Response with the AccessToken.
I need that UserId because this third party API requires it as part of their API calls (ex: users/{userId}/account).
Using DotNetOpenAuth, I don't have access to the AccessToken response so I can't get the UserId out.
I'm calling: (_client is a WebServerClient)
var state = _client.ProcessUserAuthorization(request);
state has my AccessToken, but not the extra data sent down. Based on the DotNetOpenAuth source code the UserId came in inside the library and I don't have any access.
Is there anyway to get that UserId out using DotNetOpenAuth? Or do I need to abandon DotNetOpenAuth and try something else?
You can access request and response data by implementing IDirectWebRequestHandler and assigning it to Channel. But with current implementation of DNOA, the only way I got it to work is by applying proxy pattern to an existing UntrustedWebRequestHandlerclass, this is because this particular handler passes a CachedDirectWebResponse, which has a response stream that could be read multiple times - once by your code to retrieve additional data, and later by downstream code to ProcessUserAuthorization().
This is the code for custom IDirectWebRequestHandler :
public class RequestHandlerWithLastResponse : IDirectWebRequestHandler
{
private readonly UntrustedWebRequestHandler _webRequestHandler;
public string LastResponseContent { get; private set; }
public RequestHandlerWithLastResponse(UntrustedWebRequestHandler webRequestHandler)
{
if (webRequestHandler == null) throw new ArgumentNullException( "webRequestHandler" );
_webRequestHandler = webRequestHandler;
}
public bool CanSupport( DirectWebRequestOptions options )
{
return _webRequestHandler.CanSupport( options );
}
public Stream GetRequestStream( HttpWebRequest request )
{
return _webRequestHandler.GetRequestStream( request, DirectWebRequestOptions.None );
}
public Stream GetRequestStream( HttpWebRequest request, DirectWebRequestOptions options )
{
return _webRequestHandler.GetRequestStream( request, options );
}
public IncomingWebResponse GetResponse( HttpWebRequest request )
{
var response = _webRequestHandler.GetResponse( request, DirectWebRequestOptions.None );
//here we actually getting the response content
this.LastResponseContent = GetResponseContent( response );
return response;
}
public IncomingWebResponse GetResponse( HttpWebRequest request, DirectWebRequestOptions options )
{
return _webRequestHandler.GetResponse( request, options );
}
private string GetResponseContent(IncomingWebResponse response)
{
MemoryStream stream = new MemoryStream();
response.ResponseStream.CopyTo(stream);
stream.Position = 0;
response.ResponseStream.Position = 0;
using (var sr = new StreamReader(stream))
{
return sr.ReadToEnd();
}
}
}
And this is how we apply it and get response data:
var h = new RequestHandlerWithLastResponse(new UntrustedWebRequestHandler()); ;
_client.Channel.WebRequestHandler = h;
var auth = _client.ProcessUserAuthorization( request );
//convert response json to POCO
var extraData = JsonConvert.DeserializeObject<MyExtraData>( h.LastResponseContent );
Just read the id straight from the request, line after your call to ProcessUserAuthorization, depending on how it is passed (body, query string). I don't see any reason to stop using the DNOA.
var auth = client.ProcessUserAuthorization();
if ( auth != null )
{
// this is where you could still access the identity provider's request
...
Note that passing additional parameters together with the access token is rather uncommon and could lead to potential security issues. This is because the identity provider's response first gets to the user's browser and is then submitted to your server. The user could possibly alter the identity provider's response by keeping the access token but replacing the userid with any other valid userid.