Создание безопасных веб-сервисов с ColdFusion - PullRequest
7 голосов
/ 22 июня 2011

Я создал существующий API с веб-сервисами, использующими ColdFusion, который использует встроенную аутентификацию, но я хотел бы защитить его с помощью какой-либо аутентификации, но я не знаю, с чего начать.

ColdFusion автоматически генерирует веб-сервисы, добавляя? Wsdl в конец моих cfcs.

Когда я говорю «», я имею в виду, что для каждого вызова веб-службы клиент должен передать ключ / пароль в soapenv: body, например:

<apiKey xsi:type="xsd:string">test</apiKey>
<apiPass xsi:type="xsd:string">test!ng</apiPass>

Но я думаю, что хотел бы использовать WS-Security или обычную аутентификацию, но я понятия не имею, что я делаю.

Кажется, никто не делает то, о чем я прошу, в сообществе CF, что кажется странным.

1 Ответ

4 голосов
/ 22 июня 2011

Я не фанат WSE (http://oasis -open.org /) или SOAP в целом, но это может быть полезно в ситуациях интеграции, мы использовали его, например, при использовании веб-сервисов .NET.

Я предпочитаю использовать Application.cfc в том же каталоге, что и веб-служба, для аутентификации запроса по IP и токену безопасности или имени пользователя / паролю.Мы используем это для наших веб-сервисов RESTful, которые используют другие.В качестве альтернативы вы можете просто аутентифицировать код как часть самой обработки веб-сервиса.

Если вам нужно использовать WSE, вам нужно добавить группу заголовков SOAP с использованием addSOAPRequestHeader() при отправке пакетов SOAP, а затем проверить эти же заголовки при получении ответов.Это может быть грязно, но вот код, который работает для нас:

<cffunction name="AddSecurityHeaders" access="public" returntype="any" hint="This adds the security headers as defined in the WS Security section of the WSS standard. Username and password are unencrypted." output="Yes">
        <cfargument name="webSvc" required="Yes" type="any" hint="This must be a vaild web service."> 
        <cfargument name="username" required="Yes" type="string" hint="Username required by webservice being called."> 
        <cfargument name="password" required="Yes" type="string" hint="Password required by web service being called."> 
        <cfargument name="action" required="Yes" type="string" hint="Value to be inseted into wsa:Action node."> 
        <cfargument name="to" required="Yes" type="string" hint="Value to be inseted into wsa:To node."> 
        <cfargument name="mustUnderstandSecurityHdr" required="No" type="boolean" default="false" hint="This value will be inserted into the <wsse:Security> header as the 'mustUnderstand' value."> 

        <cfscript>

        var rightNow = "" ;
        var expiryTime = "" ;
        var objXmlAction = "" ;
        var objXmlMessageID = "" ;
        var objXmlTo = "" ;
        var objXmlSecurity = "" ;
        var objXmlReplyTo = "" ;
        var objTimezone = CreateObject("component", "com.utils.timezone") ;

        // Setup times (UTC/GMT only!)
        rightNow = objTimezone.castToUTC(Now()) ;
        expiryTime = DateAdd("n", 5, rightNow) ;

        // Create XML doument and add required nodes starting with <wsa:Action>
        objXmlAction = XmlNew() ;
        objXmlAction.XmlRoot = XmlElemNew(objXmlAction,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:Action") ;
        objXmlAction.XmlRoot.XmlText = ARGUMENTS.action ;

        // ..then <wsa:MessageID>
        objXmlMessageID = XmlNew() ;
        objXmlMessageID.XmlRoot = XmlElemNew(objXmlMessageID,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:MessageID") ;
        objXmlMessageID.XmlRoot.XmlText = "uuid:" & CreateUUID() ;

        // ...then <wsa:Address>
        objXmlReplyTo = XmlNew() ;
        objXmlReplyTo.XmlRoot = XmlElemNew(objXmlReplyTo,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:ReplyTo") ;
        objXmlReplyTo.XmlRoot.XMLChildren[1] = XmlElemNew(objXmlReplyTo,  "wsa:Address") ;
        objXmlReplyTo.XmlRoot.XMLChildren[1].XmlText = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous" ;

        // ..then <wsa:To>
        objXmlTo = XmlNew() ;
        objXmlTo.XmlRoot = XmlElemNew(objXmlTo,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:To") ;
        objXmlTo.XmlRoot.XmlText = ARGUMENTS.to ;

        // ..then the main <wsse:Security> node which contains further info...
        objXmlSecurity = XmlNew(true) ;
        objXmlSecurity.XmlRoot = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:Security") ;
        // ...note: this namespace is added as it is used in children nodes and this can help avoid XmlSearch errors in CFMX
        //StructInsert(objXmlSecurity.XmlRoot.XmlAttributes, "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd") ;

         // ...Timestamp, it's children and attributes
        objXmlSecurity.XmlRoot.XMLChildren[1] = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Timestamp") ;
        StructInsert(objXmlSecurity.XmlRoot.XMLChildren[1].XmlAttributes, "wsu:Id", "Timestamp-#CreateUUID()#") ;

        objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[1] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created") ;
        objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[1].XmlText = DateFormat(rightNow, "YYYY-MM-DD") & "T" & TimeFormat(rightNow, "HH:mm:ss") & "Z" ;
        objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[2] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Expires") ;
        objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[2].XmlText = DateFormat(expiryTime, "YYYY-MM-DD") & "T" & TimeFormat(expiryTime, "HH:mm:ss") & "Z" ;
        // ...Username token, attributes and children 
        objXmlSecurity.XmlRoot.XMLChildren[2] = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:UsernameToken") ;
        StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlAttributes, "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd") ;
        StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlAttributes, "wsu:Id", "SecurityToken-#CreateUUID()#") ;
        // ...UsernameToken.Username
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[1] = XmlElemNew(objXmlSecurity, "wsse:Username") ;
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[1].XmlText = Trim(ARGUMENTS.username) ;
        // ...UsernameToken.Password 
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2] = XmlElemNew(objXmlSecurity, "wsse:Password") ;
        StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2].XmlAttributes, "Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0##PasswordText") ; 
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2].XmlText = Trim(ARGUMENTS.password) ;
        // ... Nonce 
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[3] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:Nonce") ;
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[3].XmlText = ToBase64(CreateUUID()) ;
        // ...Created 
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[4] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created") ;
        objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[4].XmlText = DateFormat(rightNow, "YYYY-MM-DD") & "T" & TimeFormat(rightNow, "HH:mm:ss") & "Z" ;

        // Add the created headers to the soap requests - note that the 2nd and 3rd parameters have no significance in this instance
        addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlAction#", false) ;
        addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlMessageID#", false) ;
        addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlReplyTo#", false) ;
        addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlTo#", false) ;
        addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlSecurity#", ARGUMENTS.mustUnderstandSecurityHdr) ;

        return ARGUMENTS.webSvc ;

        </cfscript>

    </cffunction>

Вот пример использования:

// Create web service
objWebSvc = CreateObject("webservice", "remoteWebService?WSDL") ;

// Create security object and add the security header to our SOAP request
objWSESecurity = CreateObject("component", "wse") ;

objWebSvc = objWSESecurity.AddSecurityHeaders(
    webSvc=objWebSvc,
    username="xxx", 
    password="yyy", 
    action="remoteAction", 
    to="remoteWebService", 
    mustUnderstandSecurityHdr=false
) ;

Видите ли, много кода :) Надеюсь, это поможеттем не мение.

...