I'm using .NET 2.0. There are any alternative to .NET WSE 3.0?
Is it possible to pass username and password in soap header without any toolkit, only using code?
Thanks
(This suggestion might be way off, since I'm not sure if you mean some special WS.* headers, or just any custom header... and I've never heard of WSE)
I call a webservice with user/pass in a header as follows. It's not production code, but the snippets should illustrate it.
On the client:
string userName = "someusername";
string password = "somepass";
//create the custom header object
MyService.AuthHeader authHeader = new MyService.AuthHeader();
authHeader.UserName = userName;
authHeader.Password = password;
//create the WS-proxy
MyService.SomeWebservice someWS = new MyService.SomeWebservice();
//set headers
someWS.AuthHeaderValue = authHeader;
someWS.SomeMethod();
The webservice:
public class SomeWebservice : System.Web.Services.WebService
{
public AuthHeader Authentication = null; //For receiving the authentication header from the SOAP client (you will never assign this property in user code, .NET handles the plumbing based on the [SoapHeader("Authentication")] attribute
[WebMethod(Description = "Some webservice method")]
[SoapHeader("Authentication")]
public void SomeMethod()
{
string suppliedUserName = Authentication.UserName;
string suppliedPassword = Authentication.Password;
}
}
The AuthHeader class: (defined at the "WS end")
public class AuthHeader : SoapHeader
{
public string UserName = null;
public string Password = null;
}
It's possible to alter the SOAP Message using SOAP Extensions including the required SOAP Header
Related
Currently I am fighting with the following problem:
I need to forward SOAP requests to an external service in special cases (decision based on tenantId provided in the SOAP message). I created an interceptor for this task to extract tenantId from the message request, get assignment (each tenantId is assigned to its own service instance running on a different server) and if no assignment is made, I need to process the request just as normal.
Currently I implemented on this way: I create HttpUrlConnection in the interceptor and forward the request to an external endpoint (in case there is an assignment) and take the outputStream of the response and send the response over HttpServletResponse.getOutputStream etc...
I also need to consider that the interceptor be used with various service (tenantId must be provided in the SOAP request).
I also read about Provider and Dispatch objects not sure how this should work.
Is there any way to get target service and port (QNames) from the incoming message?
I cannot use Camel at the moment (only CXF is allowed).
Maybe you can try something like this :
/** Your interceptor */
public void handleMessage(SoapMessage msg) throws Fault {
Exchange exchange = msg.getExchange();
Endpoint ep = exchange.get(Endpoint.class);
// Get the service name
ServiceInfo si = ep.getEndpointInfo().getService();
String serviceName = si.getName().getLocalPart();
XMLStreamReader xr = msg.getContent(XMLStreamReader.class);
if (xr != null) { // If we are not even able to parse the message in the SAAJInInterceptor (CXF internal interceptor) this can be null
// You have the QName
QName name = xr.getName();
SOAPMessage msgSOAP = msg.getContent(SOAPMessage.class);
// Read soap msg
if (msgSOAP != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
msgSOAP.writeTo(byteArrayOutputStream);
String encoding = (String) msg.get(Message.ENCODING);
String xmlRequest = new String(byteArrayOutputStream.toByteArray(), encoding);
}
// Forward to external service with JAX-RS implementation
Client client = ClientBuilder.newClient()
.target("http://your-target")
.path("/custom-path")
.request()
.post(Entity.entity(xmlRequest, MediaType.APPLICATION_XML));
}
}
Hope this help.
I have a WCF Service Application which server to different type of clients. While calling the service methods I want to send some spesific information within the service header.
While using a newer version of .NET Framework I can handle the situation using MessageHeader. Since the consumer can see the service as WCF Service there is no problem.
[DataContract]
public class AuthToken
{
[DataMember]
public string Username { get; set; }
[DataMember]
public string Password { get; set; }
}
Client-side:
AuthWCFSvc.Service1Client client = new AuthWCFSvc.Service1Client();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
SvcAuthClient.AuthWCFSvc.AuthToken token = new AuthWCFSvc.AuthToken();
token.Username = "wcfuser";
token.Password = "wcfpass";
MessageHeader<SvcAuthClient.AuthWCFSvc.AuthToken> header = new MessageHeader<SvcAuthClient.AuthWCFSvc.AuthToken>(token);
var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
client.TestHeader();
}
Server-side :
MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
AuthToken token = headers.GetHeader<AuthToken>("Identity", "http://www.my-website.com");
But there are Windows Mobile 6 devices with .NET Framework 3.5 Compact Edition, using these services as well. Due to technological restrictions, they only can process the WCF services as Web Services.
If a client is consuming a WCF service as Web Service how can add spesific header information and resolve the header information at the service method?
As you know, on .NET CF 3.5 you can only use WCF as standard webservice on SOAP way. Therefore, you can't use any of WCF native security resources.
I figured out how to use Basic Http Authentication, configuring client and server sides and I can explain it as follows:
Client Side
On client side (on your device with .Net CF 3.5), its easy. Just inform your credentials configuring your clientServiceProxy by using:
var service = new YourServiceNamespace.YourService();
service.Credentials = new NetworkCredential("login", "12345");
service.PreAuthenticate = true;
This will make your client deal with the "WWW-Authenticate" header from the server response and pass your credentials automatically via the response header "Authorization: Basic".
Server Side
On the WCF configuration on your web.config, you should configure security just for Transport, and use HTTPS (this is enough to protect your message from sniffers).
<basicHttpBinding>
<binding>
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
Now, as WCF doesn't has native support for Basic Http Authentication, we have to use a custom HTTP module to deal with it.
public class BasicHttpAuthentication : IHttpModule
{
public delegate bool AuthenticateDelegate( string username, string password );
public static AuthenticateDelegate AuthenticateMethod;
public void Dispose() { }
public void Init( HttpApplication application )
{
application.AuthenticateRequest += this.OnAuthenticateRequest;
application.EndRequest += this.OnEndRequest;
}
private void DenyAccess( HttpApplication app )
{
app.Response.StatusCode = 401;
app.Response.StatusDescription = "Access Denied";
// Write to response stream as well, to give user visual
// indication of error during development
app.Response.Write( "401 Access Denied" );
app.CompleteRequest();
}
private void OnAuthenticateRequest( object source, EventArgs eventArgs )
{
if ( AuthenticateMethod == null )
return;
var app = ( HttpApplication )source;
//the Authorization header is checked if present
string authHeader = app.Request.Headers["Authorization"];
if ( !string.IsNullOrEmpty( authHeader ) )
{
string authStr = app.Request.Headers["Authorization"];
if ( string.IsNullOrEmpty( authStr ) )
return; // No credentials; anonymous request
authStr = authStr.Trim();
if ( authStr.IndexOf( "Basic", 0 ) != 0 )
// header is not correct...we'll pass it along and
// assume someone else will handle it
return;
authStr = authStr.Trim();
string encodedCredentials = authStr.Substring( 6 );
byte[] decodedBytes = Convert.FromBase64String( encodedCredentials );
string s = new ASCIIEncoding().GetString( decodedBytes );
string[] userPass = s.Split( new[] { ':' } );
string username = userPass[0];
string password = userPass[1];
if ( !AuthenticateMethod( username, password ) )
this.DenyAccess( app );
}
else
{
app.Response.StatusCode = 401;
app.Response.End();
}
}
private void OnEndRequest( object source, EventArgs eventArgs )
{
//the authorization header is not present
//the status of response is set to 401 and it ended
//the end request will check if it is 401 and add
//the authentication header so the client knows
//it needs to send credentials to authenticate
if ( HttpContext.Current.Response.StatusCode == 401 )
{
HttpContext context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.AddHeader( "WWW-Authenticate", "Basic Realm=\"Please inform your credentials\"" );
}
}
}
To enable the HTTP module, add the following to your web.config file in the system.webServer section:
<system.webServer>
<modules>
<add name="BasicHttpAuthentication"
type="BasicHttpAuthentication, YourAssemblyName"/>
</modules>
Now you have to inform to the module a Function to use for validating the credentials from the client. You can see that there's a static delegate inside the module called "AuthenticateMethod", so you can inform a function on your Application_Start of your global.asax:
BasicHttpAuthentication.AuthenticateMethod = ( username, password ) => username == "login" && password == "12345";
We have MVVM Silverlight application. I am trying to open web url from button click event which happen on client side viewmodel and through invoke method needs to open web url in new browser.
I am using Process.Start method as describe below in Server side code.
var URL = #"http://SiteSelect.aspx";
SecureString secure = new SecureString();
char[] passwordChars = Properties.Settings.Default.Password.ToCharArray();
//converting string to securestring...found from internet
foreach (char c in passwordChars)
{
secure.AppendChar(c);
}
Process.Start(URL,"",Properties.Settings.Default.User,secure,"agent");
this throws an error related to user name and password. I checked user name and password is correct. Anyone have solution or any other method I can able to use?
Thanks,
You create a helper class:
public static class CommonHelper
{
private class HyperlinkButtonWrapper : HyperlinkButton
{
public void OpenURL(string navigateUri)
{
OpenURL(new Uri(navigateUri, UriKind.Absolute));
}
public void OpenURL(Uri navigateUri)
{
base.NavigateUri = navigateUri;
base.TargetName = "_blank";
base.OnClick();
}
}
public static void OpenURL(string navigateUri)
{
new HyperlinkButtonWrapper().OpenURL(navigateUri);
}
}
Usage:
CommonHelper.OpenURL(#"http://SiteSelect.aspx");
You could use this as well :
using System.Windows.Browser;
var uri = new Uri("http://foo.fr");
HtmlPage.Window.Navigate(uri, "_blank");
Easiest way to pass credentials is to put them in the URL, however it's not very secured. Ie:
http://user:password#foo.fr
I have a Custom SharePoint webservice for performing certain actions. User credentials are passed via Soap Header. The credentials reach the webservice without any problem.
Issue:
The following code returns "Unauthorized Error" if I did not make the webservice call with user credentials.
WebService Method
[WebMethod(Description = "Test Credentials")]
[SoapDocumentMethod(Binding = "SPService")]
[SoapHeader("Authen")]
public string[] TestCredentials(string siteURL)
{
string[] credentials = new string[3];
using (SPSite site = new SPSite(siteURL))
{
using (SPWeb spW = site.OpenWeb())
{
credentials[0] = Authen.CallingUserName;
credentials[1] = Authen.CallingUserPwd;
credentials[2] = siteURL;
}
}
return credentials;
}
Client Code
SPService.SPService spS = new SPService.SPService();//Webservice class
SPService.UserAuth ua = new SPService.UserAuth(); //Soap Header class
ua.CallingUserName = UserName; // User name
ua.CallingUserPwd = Password; // Password for the Username
spS.UserAuthValue = ua; // assigning the credential to the SoapHeader.
//System.Net.NetworkCredential nc = new NetworkCredential(UName, pwd, Domain);
//spS.Credentials = new NetworkCredential(UName, pwd, Domain);
string[] str = new string[3];
str = spS.TestCredentials(txt_URL.Text,"Shared Documents");
When the Network credential is commented out I get the The request failed with HTTP status 401: Unauthorized. error. If the credential is used then the webservice returns the expected value.
Requirement of the Custom WebService is to use WS-Security to pass the Login credentials and use the same to login into the SharePoint site.
Some help would be useful. Kindly let me know if you need more detail regarding this.
The SPSite constructor will require authentication to intialise correctly as it is accessing Sharepoint. You can instantiate it using credentials you have constructed before hand in a similar manner to what is described here
how can I access a webservice through a basic http authentification? I am using the netbeans built in webservice client features. But when I try to access the webservice, I get an exception with a 401 auth failed error message.
How can I pass the right username and password?
Thank you!
You could use BindingProvider or WSBindingProvider class to access a Web Service through a basic http authentification.
The code is as follows.
XxxService service = new XxxService();
Xxx port = service.getXxxPort();
Map<String, Object> reqContext = ((BindingProvider)port).getRequestContext();
reqContext.put(BindingProvider.USERNAME_PROPERTY, "username");
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
You can also provide your own Authenticator. That way it will work even if the WDSL itself is protected by basic HTTP authentication.
#WebServiceRef(wsdlLocation = "https://laka/sito?wsdl")
static XxxService service;
public static void main(String[] args) {
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user", "password".toCharArray());
}
});
service = new XxxService();
Xxx port = service.getXxxPort();
// invoke webservice and print response
XxxResponse resp = port.foo();
System.out.println(resp.toString());
}