如何使用Grails-cxf插件为Web服务提供动态凭据(用户名和密码)

lil*_*ien 5 grails groovy cxf credentials wss4j

我正在使用这个非常棒的插件http://grails.org/plugin/cxf-client来使用具有安全性的契约优先Web服务.

所以我的配置中已经有类似的东西:

 cxf {
   client {
    cybersourceClient {           
        clientInterface = com.webhost.soapProcessor
        serviceEndpointAddress = "https://webhost/soapProcessor"
        wsdl = "https://webhost/consumeMe.wsdl"
        secured = true
        username = "myUname"
        password = "myPwd"
    }   
}
Run Code Online (Sandbox Code Playgroud)

这非常有效,但我现在要做的是为我的用户提供输入用户名和密码的权限,以便他们输入用户名和密码来使用该服务.有谁知道如何做到这一点?

我怀疑它在演示项目中使用Custom In Interceptor:

package com.cxf.demo.security

import com.grails.cxf.client.CxfClientInterceptor

import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor
import org.apache.ws.security.WSPasswordCallback
import org.apache.ws.security.handler.WSHandlerConstants

import javax.security.auth.callback.Callback
import javax.security.auth.callback.CallbackHandler
import javax.security.auth.callback.UnsupportedCallbackException


class CustomSecurityInterceptor implements CxfClientInterceptor {

String pass
String user


   WSS4JOutInterceptor create() {
    Map<String, Object> outProps = [:]
    outProps.put(WSHandlerConstants.ACTION, org.apache.ws.security.handler.WSHandlerConstants.USERNAME_TOKEN)
    outProps.put(WSHandlerConstants.USER, user)
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, org.apache.ws.security.WSConstants.PW_TEXT)
    outProps.put(WSHandlerConstants.PW_CALLBACK_REF, new CallbackHandler() {

        void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]
            pc.password = pass
            pc.identifier = user
        }
    })

    new WSS4JOutInterceptor(outProps)
}
}
Run Code Online (Sandbox Code Playgroud)

但是因为我没有实例化这个拦截器,或者理解它是如何实例化的,所以我不知道如何获得拦截器中使用的用户凭据.

有谁知道如何做/有任何示例代码?

谢谢!

Ian*_*rts 0

假设您正在使用 Spring Security 插件,并且您想要使用的 WS 凭证是User域对象的属性,那么类似这样的事情应该可以工作(未经测试):

src/groovy/com/cxf/demo/security/CustomSecurityInterceptor.groovy

package com.cxf.demo.security

import com.grails.cxf.client.CxfClientInterceptor

import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor
import org.apache.ws.security.WSPasswordCallback
import org.apache.ws.security.handler.WSHandlerConstants

import javax.security.auth.callback.Callback
import javax.security.auth.callback.CallbackHandler
import javax.security.auth.callback.UnsupportedCallbackException


class CustomSecurityInterceptor implements CxfClientInterceptor {

   def springSecurityService
   def grailsApplication

   WSS4JOutInterceptor create() {
    Map<String, Object> outProps = [:]
    outProps.put(WSHandlerConstants.ACTION, org.apache.ws.security.handler.WSHandlerConstants.USERNAME_TOKEN)
    // take default username from config
    outProps.put(WSHandlerConstants.USER, grailsApplication.config.cxf.client.cybersourceClient.username)
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, org.apache.ws.security.WSConstants.PW_TEXT)
    outProps.put(WSHandlerConstants.PW_CALLBACK_REF, new CallbackHandler() {

        void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]
            // take password from current user, fall back to config if no
            // user currently logged in/not in a request thread, etc.
            pc.password = (springSecurityService.currentUser?.wsPassword
               ?: grailsApplication.config.cxf.client.cybersourceClient.password)
        }
    })

    new CustomWSS4JOutInterceptor(springSecurityService, outProps)
  }
}

class CustomWSS4JOutInterceptor extends WSS4JOutInterceptor {
  def springSecurityService

  CustomWSS4JOutInterceptor(springSecurityService, outProps) {
    super(outProps)
    this.springSecurityService = springSecurityService
  }

  // overridden to fetch username dynamically from logged in user
  // but fall back on config if no user/not on a request hander thread
  public Object getOption(String key) {
    if(key == WSHandlerConstants.USER && springSecurityService.currentUser?.wsUser) {
      return springSecurityService.currentUser?.wsUser
    } else return super.getOption(key)
  }
}
Run Code Online (Sandbox Code Playgroud)

grails-app/conf/spring/resources.groovy

import com.cxf.demo.security.CustomSecurityInterceptor
beans = {
  customSecurityInterceptor(CustomSecurityInterceptor) {
    springSecurityService = ref('springSecurityService')
    grailsApplication = ref('grailsApplication')
  }
}
Run Code Online (Sandbox Code Playgroud)

并在配置中替换secured = truesecurityInterceptor = 'customSecurityInterceptor'

如果您不使用 Spring Security,则相同的模式也可以工作。关键的部分是回调处理程序

            pc.password = (springSecurityService.currentUser?.wsPassword
               ?: grailsApplication.config.cxf.client.cybersourceClient.password)
Run Code Online (Sandbox Code Playgroud)

和用户名逻辑getOption

    if(key == WSHandlerConstants.USER && springSecurityService.currentUser?.wsUser) {
      return springSecurityService.currentUser?.wsUser
Run Code Online (Sandbox Code Playgroud)

例如,如果用户名和密码存储在 HTTP 会话中,那么springSecurityService您可以使用 Spring RequestContextHolder来代替,它的静态getRequestAttributes()方法返回当前线程正在处理的 GrailsWebRequest ,如果当前线程未处理请求,则返回 null (例如,如果它是后台作业)。

RequestContextHolder.requestAttributes?.session?.wsUser
Run Code Online (Sandbox Code Playgroud)

request.wsUser = 'realUsername'或者,如果它们是请求属性(即您在控制器中所说的),您可以使用RequestContextHolder.requestAttributes?.currentRequest?.wsUser.