How to display the username credentials used in a SOAP WCF call? - wcf

The SOAP call below works fine using my credentials but when other people use my .EXE which calls the WCF service I get a 401 denied. I am trying to find out what are the credentials being passed.
I could look at the IIS logs but am trying to do it programatically, thanks:
public static Guid GetServerID(string serverName, string soapUrl)
{
Guid result;
try
{
Guid vServerId = new ControllerWS.Controller
{
Url = soapUrl,
Timeout = Config.SoapCallTimeOut,
Credentials = CredentialCache.DefaultCredentials
}.GetServerId(serverName);
result = vServerId;
//Console.WriteLine("CredentialCache.DefaultCredentials: " + CredentialCache.DefaultCredentials.ToString());
//ICredentials Credentials = CredentialCache.DefaultCredentials.GetCredential()
}

It realy depends what type of authentication you are using. When windows credentials with impersonation then you can get username like this:
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name
If you are using plain username and password than those values can be stored inside request header and read like this:
MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string userId = headers.GetHeader<Guid>("MyKey", "MyNamespce");

You can use an IDispatchMessageInspector on the server side to intercept the full message including headers. From there you can inspect the credentials that are being passed in.
Here's a blog post outlining how to log the full message from the message inspector including the configuration steps you need to do to wire it up.

Related

Dynamic "AddAuthentication()" credentials in .Net Core possible?

I am using .AddFacebook() extension method in my Startup class. In here I set the AppId and AppSecret.
Is there any way to set these options depending on the current web request instead?
The correct way to solve the underlying problem is to specify each credentials as a separate provider.
Example:
.AddFacebook("My Facebook Provider", facebookOpts => {
facebookOpts.AppId = myAppId;
facebookOpts.AppSecret = myAppSecret;
facebookOpts.CallbackPath = "signin-facebook-myFacebookProvider";
});
It's important to override the CallbackPath! If you have multiple calls to .AddFacebook, they will all try to hit the same callback path and you will get a server error.

.Net Core ReportExecutionServiceSoapClient set credentials

I am using ReportExecutionServiceSoapClient in .Net Core i got the latest version of .net Core and tried to get a report from reporting services to work. after I've used the WCF connection service I was able to add the code with looks like bellow
// Instantiate the Soap client
ReportExecutionServiceSoap rsExec = new ReportExecutionServiceSoapClient(ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap);
// Create a network credential object with the appropriate username and password used
// to access the SSRS web service
string historyID = null;
TrustedUserHeader trustedUserHeader = new TrustedUserHeader();
ExecutionHeader execHeader = new ExecutionHeader();
// Here we call the async LoadReport() method using the "await" keyword, which means any code below this method
// will not execute until the result from the LoadReportAsync task is returned
var taskLoadReport = rsExec.LoadReportAsync(reportPath, historyID);
// By the time the LoadReportAsync task is returned successfully, its "executionInfo" property
// would have already been populated. Now the remaining code in this main thread will resume executing
string deviceInfo = null;
string format = "EXCEL";
// Now, similar to the above task, we will call the RenderAsync() method and await its result
var taskRender = await rsExec.RenderAsync(renderReq);
When it hist renderAsync all falls apart because the credentials for the service are not set anywhere. I've tried to Login async with no success. Also I've tried to set the credentials with SetExecutionCredentialsAsync but I've got and error saying "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'." I don't know how to change that for ReportExecutionServiceSoapClient.
I have read some posts in which Microsoft guys says that the authentication with a soap is not resolved but for me it seems so close to be true. I feel like I am missing something.
Technology stack: VS 2017, .net Core web api, ssrs 2016, sql server 2016 standard
How can I authenticate the user for this call?
I know this is an old question but I had the same issue and stumbled onto the answer.
After creating the ReportExecutionServiceSoap object you can specify the username and password in the ClientCredentials. I've had success with this using the Basic client credential type. Be sure you are using HTTPS, otherwise your password is sent in plaintext to the reporting server. I also recommend storing the user/password in a secure place and not code.
BasicHttpBinding rsBinding = new BasicHttpBinding();
rsBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
rsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress rsEndpointAddress = new EndpointAddress("https://servername/ReportServer/ReportExecution2005.asmx");
var rsExec = new ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress);
rsExec.ClientCredentials.UserName.UserName = "username";
rsExec.ClientCredentials.UserName.Password = "pass";

Invalid twitter oauth token for Abraham's Oauth class

Here's my current operations:
1./ User accepts app and the app callback stores the oauth_token and oauth_token_secret into the database (as access_token and access_token_secret).
2./ We use a cli script to handle autoposting to twitter. We load the twitter oauth object as follows:
public function post()
{
$consumerKey = $this->getConsumerKey();
$consumerSecret = $this->getConsumerSecret();
$accessToken = $this->getAccessToken();
$accessSecret = $this->getAccessSecret();
$twitteroauth = new TwitterOAuth($consumerKey,$consumerSecret,$accessToken,$accessSecret);
$message = $this->getPostMessage();
$result = $twitteroauth->post('statuses/update', array('status' =>$message));
$this->log($result);
}
Now this assumes we are using the API consumer key and secret assigned to the app and the user's stored access tokens.
The result we are getting is:
Invalid or expired token
I don't quite understand why we are receiving this. We are using the access token and access token secret provided to us by twitter.
I did notice that there is a GET parameter oauth_verifier. This isn't something we need to be using somewhere?
In any case, I'm not quite sure whats wrong here.
Do I need to log in or something before doing posting?
your code is correct.
The problem is that the library's Util.urlParameterParse() method is broken.

Understanding how rampart engine works

I know that Apache Rampart configuration allows providing a password callback handler class, that can be used to provide passwords needed for Rampart engine to build username tokens and create signatures when sending messages.
It's written that Whenever Rampart Engine needs a password to create a username token, it will create a WSPasswordCallback instance setting the appropriate identifier which it extracts from the parameter of the Rampart configuration and pass it to the password callback class via the handle method. But as you see I've used policy based configuration!
SO I've got a few questions to see if I have understand all all that:
Is i from here where rampart engine extracts the appropriate username - wsse:Username>bob</wsse:Username>'+
After it extracts it it passes it to our PWCBHandler class via handle method.
Our handle method sets the appropriate password if the username is correct.
And the most important - as I have to consume my web service from javascript at the end I have provided my soap request. But as you see I provide both the username and the password and I can't see where is security as everyone can see my username and password. Is this right. How can I make it more secure.
here is my code.
Here is my code for PassWordCallback.java class
ublic void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
if(pwcb.getIdentifier().equals("test") &&pwcb.getPassword().equals("pass")) {
return;
}
else {
throw new UnsupportedCallbackException(callbacks[i],"Incorrect login/password");
}
}
}
here is my soaprequest from javascript
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soapenv:Envelope " +
"xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
"xmlns:tan=\"http://tan\">"+
"<soapenv:Header>"+
'<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" soapenv:mustUnderstand="1">'+
'<wsse:UsernameToken xmlns:wsu="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="123">'+
'<wsse:Username>bob</wsse:Username>'+
'<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">bobPW</wsse:Password>'+
'</wsse:UsernameToken>'+
'</wsse:Security>'+
"</soapenv:Header>"+
"<soapenv:Body>" +
"<tan:testws>" +
'<tan:x>ECHOO</tan:x>' +
' </tan:testws>'+
'</soapenv:Body>' +
'</soapenv:Envelope>';
I'll answer your 3rd question first
You are using username token authentication method to authenticate the service. To provide security you need to use https transport instead of http. this way you can provide transport level security and hide your password. Some nice reading can be found here http://wso2.com/library/3190/
If you are using insecure channel (say http) then you can encrypt the password. user can create a digest of the password with a random bytes (nounce).To authenticate the request the service will compute the digest value using the password bound to the received usename and will compare the received digest value and the computed digest value. the security headers will be changed. some detailed info can be found in this about this. http://wso2.com/library/240/ . to provide more security you can encrypt the message (http://wso2.com/library/3415/)
For question 1, it does not get the user name from wsse:Username. it extracts the username from the parameter of the Rampart configuration. This configuration can be loaded externally or using java
RampartConfig rc = new RampartConfig();
rc.setUser("admin");
rc.setPwCbClass(PWDCallBackHandler.class.getName());
some info regarding callback handler http://wso2.com/library/3733/
for question 2: yes

Testing WCF with SoapUI

I need your help on one practical issue. I have created a WCF service with basic binding with two operation contact.
1- void StartRegistration - Anonymous member can fill the basic registration form and press submit. All the information will be stored into the database and one link with some random token will be send to user's email address.
2 - void CompleteRegistration - This method validates the token sent into the email address and if token is valid, user account will be activated.
Now I have issue here. Using SoapUI I can call StartRegistration method. Email is sent to destination but I want to pass the token to CompleteRegistration method.
Since it is a WCF service so can not do dependency injection to pass the SoapUI tests :).
Please help.
If I understand your question correctly, you have two WCF methods, one for creating a token and another for confirming it.
What I would do in this case is have the first method, StartRegistration, return the token. Then you could use that token to pass into the CompleteRegistration method quite easily in Soap UI.
Another, quite messy solution, would be to have a groovy script test step in Soap UI that actually connected to the mail account, read the link and parsed the contents.
Edited:
Here is part of the script you'll need. Place it in a groovy step, that will then return the token from your mail.
Note: This code assumes that mail is plain text, not multipart. It also assumes that the mail box only has a single mail. The API for JavaMail is pretty extensive, so if you want to do any magic with it, Google is your friend :) At least, this is somewhere to start.
import javax.mail.*;
import javax.mail.internet.*;
// setup connection
Properties props = new Properties();
def host = "pop3.live.com";
def username = "mymailadress#live.com";
def password = "myPassword";
def provider = "pop3s";
// Connect to the POP3 server
Session session = Session.getDefaultInstance props, null
Store store = session.getStore provider
Folder inbox = null
String content
try
{
store.connect host, username, password
// Open the folder
inbox = store.getFolder 'INBOX'
if (!inbox) {
println 'No INBOX'
System.exit 1
}
inbox.open(Folder.READ_ONLY)
Message[] messages = inbox.getMessages()
content = messages[0].getContent()
//Do some parsing of the content here, to find your token.
//Place the result in content
}
finally
{
inbox.close false
store.close()
}
return content; //return the parsed token