2011-06-22 12 views
6

Creé una API existente con servicios web utilizando ColdFusion que usa autenticación en línea, pero me gustaría protegerla mediante algún tipo de autenticación, pero no tengo ni idea de dónde empezar.Creando servicios web seguros con ColdFusion

Los servicios web son generados automáticamente por ColdFusion añadiendo? Wsdl al final de mis cfcs.

Cuando digo "" Quiero decir que por cada llamada de servicio web que el cliente debe pasar en una llave/pass dentro del soapenv: el cuerpo como esto:

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

Pero creo que me gustaría utilizar WS-Security o autenticación básica, pero no tengo idea de lo que estoy haciendo.

Parece que no hay nadie haciendo lo que estoy pidiendo en la comunidad de CF, lo que parece extraño.

Respuesta

3

No soy fanático de WSE (http://oasis-open.org/) o SOAP en general, pero puede ser útil en situaciones de integración, lo hemos usado al consumir servicios web .NET, por ejemplo .

Mi preferencia es utilizar un Application.cfc en el mismo directorio que el servicio web para autenticar la solicitud por IP y token de seguridad o nombre de usuario/contraseña. Usamos esto para nuestros servicios web RESTful que otros consumen. Alternativamente, puede codificar la autenticación como parte del procesamiento del servicio web.

Si tiene que usar WSE, deberá agregar un montón de encabezados SOAP usando addSOAPRequestHeader() al enviar paquetes SOAP, y luego verificar estos mismos encabezados al obtener respuestas. Esto puede ser un poco incómodo, pero aquí es un código que funciona para nosotros:

<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> 

Aquí se muestra un ejemplo de uso:

// 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 
) ; 

Ves - un montón de código :) Espero que ayuda de todos modos.

+0

¡Gracias por responder! Entiendo lo que hace su función, pero no estoy seguro de dónde colocarla o cómo llamarla. Estoy sirviendo mis servicios web de esta manera http://mysite.com/news.cfc?wsdl - ahora cómo obtener esta función para interceptar la llamada al cfc? Perdón por mi confusión y gracias de nuevo. – petron

+0

He actualizado el código anterior, pero es interesante observar que nos hemos alejado de WSE con esta integración: se consideró como una fuente de problemas y no valía la pena. Ahora se autentican como parte de su solicitud de servicio en función de las credenciales de autenticación que aprobamos. –