Implementing WS-Security with JSR 181 Annotations using WSS4J in XFire(转)

The Logemann Blog really helped me out when I was trying to use JSR181 Annotations in favor of the services.xml configuration in XFire. Reading that blog entry is most likely a prerequisite for this one. Once you’ve configured your Spring beans and web.xml to use JSR181 Annotations, the next step is to implement security for your web services. The example shown implements WS-Security as specified by OASIS Web Services Security and implemented by WSS4J in XFire .

Looking at the ws-security example packaged with XFire, for a service to be security enabled, you need the following configuration in your services.xml. We are dealing with the “User Token with Hashed Password” scheme.

<service>
 <name>BookServiceUTHP</name>
 <namespace>

http://xfire.codehaus.org/BookService

 </namespace>
 <serviceClass>
  org.codehaus.xfire.demo.BookService
 </serviceClass>
 <inHandlers>
  <handler handlerClass=
    "org.codehaus.xfire.util.dom.DOMInHandler" />
  <bean class=
   "org.codehaus.xfire.security.wss4j.WSS4JInHandler">
   <property name="properties">
    <props>
     <prop key="action">UsernameToken</prop>
     <prop key="passwordCallbackClass">
      org.codehaus.xfire.demo.PasswordHandler
     </prop>
    </props>
   </property>
  </bean>
  <handler handlerClass=
   "org.codehaus.xfire.demo.ValidateUserTokenHandler"/>
 </inHandlers>
</service>

However, we want to substitute this configuration with annotations. There are three InHandlers being applied which we must specify via annotations. The problem is that when specifying handlers using annotations you may not supply any parameters to them, as we do above in the case of WSS4JInHandler. The solution is to create a custom handler which wraps the other handlers and passes in the parameters to WSS4JInHandler programmatically. Here’s a custom handler which does just that:

public class WSSecurityHandler
                  extends AbstractHandler {
 List<Handler> inHandlers;

 public WSSecurityHandler() {
  WSS4JInHandler wss4jInHandler;
  ValidateUserTokenHandler userTokenHandler;
  Properties props = new Properties();
  props.put("action", "UsernameToken");
  props.put("passwordCallbackClass",
  PasswordHandler.class.getName());

  wss4jInHandler = new WSS4JInHandler(props);
  userTokenHandler = new ValidateUserTokenHandler();
  inHandlers = new ArrayList<Handler>();
  inHandlers.add(wss4jInHandler);
  inHandlers.add(userTokenHandler);
 }

public QName[] getUnderstoodHeaders() {
  return new QName[] {
    new QName("http://docs.oasis-open.org/wss/2004/01/" +
     	      "oasis-200401-wss-wssecurity-secext-1.0.xsd",
     	      "Security")
  };
 }
 public void invoke(MessageContext messageContext)
                                   throws Exception {
  for (Handler handler : inHandlers) {
   handler.invoke(messageContext);
  }
  // User should be set by ValidateUserTokenHandler
  // You can also choose to do all your security checks in
  // ValidateUserTokenHandler which does a lot of the work for you
  if (messageContext.getProperty(
        WSHandlerConstants.ENCRYPTION_USER) == null) {
    throw new Exception("Principal not found");
  }

 }
}

The implementation is fairly straightforward. The one thing to note is the getUnderstoodHeaders() method which returns a QName. The reason this is important is that Java clients send this as part of the SOAP header and it is mandatory for the web service to recognize this as a valid header. I encountered this problem and reported it on the mailing list with no response.

The last piece of the puzzle is that we must annotate our web service class with our custom handler. Here’s an example:

@WebService
@InHandlers(handlers={
 "my.package.WSSecurityHandler",
 "org.codehaus.xfire.util.dom.DOMInHandler"
})
public class BookService {
 // methods go here
}

The DOMInHandler must be configured via an annotation. The client code for calling a web service configured using services.xml is the same as when configured via annotations:

Service serviceModel = new ObjectServiceFactory().
				create(IBook.class,
				 "BookService",
				 SERVICE_NAMESPACE,
				 null);
IBook service = (IBook) new XFireProxyFactory().
create(serviceModel, SERVICE_URL);

Client client = ((XFireProxy)
     Proxy.getInvocationHandler(service)).getClient();
client.addOutHandler(new DOMOutHandler());
Properties p = new Properties();
// Action to perform : user token
p.setProperty(WSHandlerConstants.ACTION,
		WSHandlerConstants.USERNAME_TOKEN);
// Set password type to hashed
p.setProperty(WSHandlerConstants.PASSWORD_TYPE,
				WSConstants.PW_DIGEST);
// Username in keystore
p.setProperty(WSHandlerConstants.USER, "serveralias");
// Used do retrive password for given user name
p.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS,
	          PasswordHandler.class.getName());

client.addOutHandler(new WSS4JOutHandler(p));
Book b = service.findBook("0123456789");

That’s all it takes.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值