Understanding how rampart engine works - axis2

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

Related

WSO2 Send Recovery Notification

In our current WSO2 setup, after a user performs a self creation, we place his account into a locked state, and send a confirmation email to the address specified during creation. This email has a link which allows the user to verify his account.
For development purposes, we are attempting to get the workflow down using the UserInformationRecoveryService wsdl in SOAP UI. The service which we seem to want is called sendRecoveryNotification. Here is the signature of this service:
sendRecoveryNotification(String username, String key, String notificationType)
The username parameter is simply the username of the WSO2 user in question, which we have. For the notificationType we have been using email, which presumably would trigger an email to be sent to the user. The problem is with the key parameter. It is not clear what value should be used as key, and all our guesses always lead to this error response:
18001 invalid confirmation code for user : tbiegeleisen#abc.com#tenant.com
We also noticed that several other services also expect a key, and it is not clear how to get this value.
Can someone shed light on the workflow for user recovery in WSO2? It seems to be a Catch-22 with regard of requiring a token in order to generate a new token to be sent to a user.
The WSO2 documentation clearly spells out the workflow for recovery with notification. The key which needs to be used is the return value from a call to the verifyUser() SOAP web service. This service itself expects a Captcha which normally would be sent from the UI. Here is a code snippet showing how a recovery notification can be sent:
String cookies = client.login("admin#tenant.com#tenant.com", "admin");
UserInformationRecoveryUtil userInfoutil = new UserInformationRecoveryUtil(webserviceUrl, cookies);
CaptchaInfoBean captchaInfo = new CaptchaInfoBean();
captchaInfo.setImagePath(captchaPath);
captchaInfo.setSecretKey(captchaKey);
captchaInfo.setUserAnswer(captcha);
String username = emailId + "#" + tenantDomain;
String key = userInfoutil.verifyUser(username, captchaInfo);
// now pass the key based on the Captcha along with the type of recovery action
userInfoutil.sendRecoveryNotification(username, key, "accountUnLock");

Authentication against VDS LDAP

I want to authenticate user against VDS(virtual directory server) using Java.
How VDS is different from LDAP? Or VDS is also working on LDAP
protocol?
Please help with any sample Java code for authentication against VDS
A sample code to authenticate against LDAP is as below
String userName = "John P R-Asst General Manager";
String passWord = "asdfgh123";
String base ="OU=SOU,DC=example,DC=com";
String dn = "cn=" + userName + "," + base;
String ldapURL = "ldap://mdsdc3.example.com:389";
authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
authEnv.put(Context.PROVIDER_URL, ldapURL);
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
authEnv.put(Context.SECURITY_PRINCIPAL, dn);
authEnv.put(Context.SECURITY_CREDENTIALS, password);
try {
DirContext authContext = new InitialDirContext(authEnv);
return true;
} catch (NamingException namEx) {
return false;
}
To authenticate against VDS, is a complete dn required. Because as per experts only username and password needs to be send to VDS. It will automatically find its DN and do the authentication.
Will be thankful if anyone provide nice reference material regarding ldap and vds
A virtual directory server is a type of server that provides a unified view of identities regardless of how they are stored. (Or you may prefer Wikipedia's definition: "a software layer that delivers a single access point for identity management applications and service platforms"
LDAP is a protocol (hence the "P") for communicating with directory servers.
There isn't a necessary link between LDAP and a VDS, but it is likely that a VDS provides and LDAP interface and, potentially, other programmatic interfaces (Kerberos in particular comes to mind). The details of how you communicate with the VDS are going to be dependent on the configuration you are trying to talk to, but LDAP is a good bet.
Regarding needing a full DN, you don't even need a full DN to authenticate against plain Active Directory. The more usual mode would be to supply something like DOMAIN\username (using the sAMAccountName) or username#dc.example.com (that is, the user principal name) as the SECURITY_PRINCIPAL. In your example, the user would need to type John P R-Asst General Manager rather than anything they are likely to regard as their "user name."
You do, however, need to work out what the VDS you are trying to communicate with requires as the user name. Does it need DOMAIN\username, something else? These are details that whoever runs the VDS you are communicating with should be able to provide you.
In code, you should wind up with something like this (assuming you can use LDAP):
String userName = "DOMAIN\johnp";
String passWord = "asdfgh123";
String ldapURL = "ldaps://vds.example.com";
authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
authEnv.put(Context.PROVIDER_URL, ldapURL);
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
authEnv.put(Context.SECURITY_PRINCIPAL, username);
authEnv.put(Context.SECURITY_CREDENTIALS, password);
try {
DirContext authContext = new InitialDirContext(authEnv);
return true;
} catch (NamingException namEx) {
return false;
}

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

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.

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

How do I access the user's password from LDAP in a LdapUserDetailsMapper using spring security?

We are using spring security in our web application based on spring MVC.
We are doing authentication using LDAP module of spring security which is working properly. Now I need to get the user password from LDAP for saving in the database.
For this I am using this in my code.
public class PersonContextMapper implements UserDetailsContextMapper {
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authorities) {
Person.Essence p = new Person.Essence(ctx);
p.setUsername(username);
p.setAuthorities(authorities);
Object passwordValue = ctx.getObjectAttribute("userPassword");
return p.createUserDetails();
}
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
Assert.isInstanceOf(Person.class, user, "UserDetails must be a Person instance");
Person p = (Person) user;
p.populateContext(ctx);
}
}
But I am not getting the any value for the password. Its always null.
Please help.
PS. My authentication is successful. It means password entered in the login form is matches properly with the password stored in the LDAP.
It might be that the authentication state of the connection does not have permission to read the value of the userPassword attribute. Most often, applications issue a BIND request to the directory server, including appropriate controls as necessary. The password is included in the BIND request and the directory server changes the authentication state of the connection upon successful completion of the BIND request. In any case, the value of the userPassword attribute is encrypted or hashed more often than not, and applications have no need to read the value.