从 iOS,Objective-C, IPhone, iPad, Android, Java, Node.js 或其他平台,或通过其他开发语言,使用WS-Trust请求一个ADFS的令牌
来源:互联网 发布:淘宝h5页面是什么 编辑:程序博客网 时间:2024/06/05 02:16
(原文:http://leandrob.com/2012/02/request-a-token-from-adfs-using-ws-trust-from-ios-objective-c-iphone-ipad-android-java-node-js-or-any-platform-or-language/)
这不是一个为了SEO而使用的友好名称。在这个帖子中,我希望能向你们展示一个非常简单的方法,无论你的平台或者开发语言是什么,通过这个方法都可以在你的应用中提供Active Directory的认证,唯一的要求是你可以使用HTTP的POST方法。
请求一个安全令牌
谈及ADFS,我们必定会说到 WS-Trust协议,在.NET平台上,感谢WCF和Windows Identity Foundation框架,这件事变得非常简单;但是在平台无关的情况下,WS-Trust也没有那么难。
我们首先要知道的是,WS-Trust协议 定义了一个标准的方法来获取安全令牌,这个方法基于一个XML结构,叫做Request Security Token 或者叫 RST,以下是这种结构的一个例子:
<trust:RequestSecurityTokenxmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"> <wsp:AppliesToxmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <a:EndpointReference> <a:Address>https://yourcompany.com</a:Address> </a:EndpointReference> </wsp:AppliesTo> <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType> <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType> <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType></trust:RequestSecurityToken>
关注本文的基本要素,上面这段XML中有几个域是非常重要的。在RequestSecurityToken 元素中,你可以找到一个AppliesTo 的标记,在这里,使用WS-Addressing标准,我们定义了令牌的有效范围。在这个例子中,是:https://yourcompany.com.
RequestType 指定了你需要进行的操作,在本例中,Issue,这里的意思是希望安全令牌服务((Security Token Service,或简称 STS)提供一个新的令牌;另一个RequestType 的选项是Renew,这个选项让STS服务刷新一个已有的已经存在的令牌。
最后, TokenType 指定了你所需要的令牌的类型。在我们的例子中,我们申请了一个基于SAML 2.0 格式的令牌。
看上去不是很难,是吧。但是我们在哪里说我们是谁呢?好吧,一个更具体的,增加了一点复杂性的情况是,所有的WS-*协议栈的都是用SOAP协议上构建的,所以为了发送令牌请求,我们需要讲一讲SOAP。同样的,SOAP也不是很难,SOAP也是基于XML的。我不打算解释SOAP协议了,大家如果有兴趣,可以在 http://www.w3.org/2003/05/soap-envelope/找到SOAP的格式说明。
在我们的例子中,要通过一个本地客户端与ADFS通讯,我们需要提供针对用户名与密码(加密的),因此包装好的SOAP消息就像下面看到的那样:(为了更好的表达我要说明的问题,我裁剪了部分的参数)
<s:Envelopexmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="..."> <s:Header> <a:Actions:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action><a:To s:mustUnderstand="1">https://yourcompany.com/adfs/services/trust/13/UsernameMixed</a:To> <o:Securitys:mustUnderstand="1" mlns:o="..."> <o:UsernameTokenu:Id="uuid-6a13a244-dac6-42c1-84c5-cbb345b0c4c4-1"> <o:Username>Leandro Boffi</o:Username> <o:PasswordType="...">P@ssw0rd!</o:Password> </o:UsernameToken> </o:Security> </s:Header> <s:Body><trust:RequestSecurityTokenxmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"> <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <a:EndpointReference> <a:Address>https://yourcompany.com</a:Address> </a:EndpointReference> </wsp:AppliesTo> <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType> <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType> <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType> </trust:RequestSecurityToken> </s:Body></s:Envelope>
为了快速理解这些格式,SOAP包有两个主要的属性:Head和Body。我们的消息的Body部分包含了 RST (Request for Security Token)消息,就像我们在上文创建的那样。在Head的部分,我们会发现上下文的参数,例如服务端的Uri,在那个端点可以直接执行的Action,注意在SOAP中,在一个端点可以有多个Action,以及我们是谁 (加密的),在本例中就是用户名和密码。
为了使用用户名和密码认证,我们需要在提供的服务端找到一个Action,例如:https://yourcompany.com/adfs/services/trust/13/UsernameMixed, 因此我们需要确保ADFS已经配置。
一旦我们有了SOAP消息,我们只要用普通的HTTP的POST方法发送到服务器上。以下是在DOTNET的做法,但是类似的操作可以在其他平台上进行;或者通过其他的开发语言:
var client = new WebClient(); client.Headers.Add("Content-Type", "application/soap+xml; charset=utf-8"); var result = client.UploadString( address:"https://yourcompany.com/adfs/services/trust/13/UsernameMixed", method:"POST", data:soapMessage);
确保你的Html有中的Content-Type是 “application/soap+xml; charset=utf-8”,你最终发送到服务器上的消息是像这样的:
POST /adfs/services/trust/13/UsernameMixed HTTP/1.1 Connection: Keep-AliveContent-Length: 1862Content-Type: application/soap+xml; charset=utf-8Accept-Encoding: gzip, deflateExpect: 100-continueHost: localhost <s:Envelope ...> ... </s:Envelope>
为了和HTTP协议一致,我增加了一些其他的标题。但是Content-Type是ADFS所必须的。
对请求安全令牌的响应
如果你的证书能够通过验证,而你的Uri也是范围内规定的,那么你会从ADFS收到一个SOAP结构的响应。这个响应的Body部分看上去像这样:
<trust:RequestSecurityTokenResponseCollectionxmlns:trust="..."> <trust:RequestSecurityTokenResponse> <trust:Lifetime>...</trust:Lifetime><wsp:AppliesToxmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">...</wsp:AppliesTo> <trust:RequestedSecurityToken> <AssertionID="_fcf06a39-c495-4074-8f22-4a7df6e26513" IssueInstant="2012-02-21T04:27:24.771Z" Version="2.0"xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> <Issuer>http://yourcompany.com/adfs/services/trust</Issuer> <ds:Signaturexmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:ReferenceURI="#_fcf06a39-c495-4074-8f22-4a7df6e26513"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:TransformAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethodAlgorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>...</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>...</ds:SignatureValue> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate>...</ds:X509Certificate> </ds:X509Data> </KeyInfo> </ds:Signature> <Subject> <SubjectConfirmationMethod="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <SubjectConfirmationData NotOnOrAfter="2012-02-21T04:32:24.771Z"/> </SubjectConfirmation> </Subject> <Conditions NotBefore="2012-02-21T04:27:24.756Z"NotOnOrAfter="2012-02-21T05:27:24.756Z"> <AudienceRestriction> <Audience>https://yourcompany.com/</Audience> </AudienceRestriction> </Conditions> <AttributeStatement> <AttributeName="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"> <AttributeValue>Leandro Boffi</AttributeValue> </Attribute> <AttributeName="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"> <AttributeValue>Administrator</AttributeValue> <AttributeValue>Mobile User</AttributeValue> </Attribute> </AttributeStatement> <AuthnStatement AuthnInstant="2012-02-21T04:27:24.724Z"> <AuthnContext> <AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:Password </AuthnContextClassRef> </AuthnContext> </AuthnStatement> </Assertion> </trust:RequestedSecurityToken> <trust:RequestedAttachedReference>...</trust:RequestedAttachedReference> <trust:RequestedUnattachedReference>...</trust:RequestedUnattachedReference> <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType> <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType> <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType> </trust:RequestSecurityTokenResponse></trust:RequestSecurityTokenResponseCollection>
这个格式在WS-Trust协议中也被称为Request Security Token Response 或者RSTR,但是对你来说,在响应中最重要的内容在这里:RequestSecurityTokenResponseCollection/RequestSecurityToeknResponse/RequestedSecurityToken. 这个标签的内容是安全令牌,在我们的例子中,它是这样的:
<AssertionID="_fcf06a39-c495-4074-8f22-4a7df6e26513"IssueInstant="2012-02-21T04:27:24.771Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> <Issuer>http://yourcompany.com/adfs/services/trust</Issuer> <ds:Signaturexmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethodAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethodAlgorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:ReferenceURI="#_fcf06a39-c495-4074-8f22-4a7df6e26513"> <ds:Transforms> <ds:TransformAlgorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:TransformAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethodAlgorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>...</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>...</ds:SignatureValue> <KeyInfoxmlns="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate>...</ds:X509Certificate> </ds:X509Data> </KeyInfo> </ds:Signature> <Subject> <SubjectConfirmationMethod="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <SubjectConfirmationDataNotOnOrAfter="2012-02-21T04:32:24.771Z"/> </SubjectConfirmation> </Subject> <ConditionsNotBefore="2012-02-21T04:27:24.756Z"NotOnOrAfter="2012-02-21T05:27:24.756Z"> <AudienceRestriction> <Audience>https://yourcompany.com/</Audience> </AudienceRestriction> </Conditions> <AttributeStatement> <AttributeName="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"> <AttributeValue>Leandro Boffi</AttributeValue> </Attribute> <AttributeName="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"> <AttributeValue>Administrator</AttributeValue> <AttributeValue>Mobile User</AttributeValue> </Attribute> </AttributeStatement> <AuthnStatement AuthnInstant="2012-02-21T04:27:24.724Z"> <AuthnContext> <AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:Password </AuthnContextClassRef> </AuthnContext> </AuthnStatement></Assertion>
一旦我们从响应内容中分解出了令牌,所有的一切都变得更简单了:在AttributeStatment 节,你会得到一个Attribute的列表。这是申明,用户的信息,例如在这个令牌中我们有以下三个申明:
· 类型: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
· 值: Leandro Boffi
· 类型: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
· 值: Administrator
· 类型: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
· 值: Mobile User
你可以使用这些申明来处理你应用里的认证,但是同样如果你的应用要调用一个依赖于你的ADFS的WebService的话。每个请求你都需要把整个令牌发送给WebService(我会在接下来的帖子里解释这个情景)。
安全特性:
令牌有一些安全特性,使用这些特性,可以使我们的应用更加安全。我不打算在这个帖子里解释所有这些特性,但是作为一个例子,如果我们希望验证一下令牌自发出之后没有人修改过它,或者说它是由它的发出方签名的(在我们这个例子中,是ADFS),那么你可以在 Assertion/Signature/SignatureValue找到一个签名。这个签名也是基于一个叫做XML签名的标准的。你可以在下面的网站找到它的描述:http://www.w3.org/Signature/.
另一个非常重要的特性是,为了避免其他人利用旧的令牌,令牌只有很多的生存时间。你可以在Assertion/Conditions/NotBefore 和NotOnOrAfter找到(令牌的生存时间)相关的信息。
结论:
不论哪个平台或是哪种开发语言,把我们应用的身份认证集成到Active Directory是可以实现的,这是因为ADFS是基于WS-Trust这样一个标准的协议。如果你的开发语言本身不支持WS-Trust,可能需要进行一些尝试,但是如同我们所见的那样,根本不是很难。你只需要一个为SOAP+RST定制的XML模板,并且可以调用一个HTTP POST就可以了。
这里
这里 可以下载到一个模板,用于调用SOAP-RST,只要用你需要的值替换掉括号内的(值),并且开始请求令牌!
希望这能对你们有益!
- 从 iOS,Objective-C, IPhone, iPad, Android, Java, Node.js 或其他平台,或通过其他开发语言,使用WS-Trust请求一个ADFS的令牌
- iOS的绘图机制-iOS,iPad,iPhone,Objective-c
- iOS的绘图机制二 - iOS,iPad,iPhone,Objective-c
- iOS的绘图机制-iOS,iPad,iPhone,Objective-c
- iOS的绘图机制二 - iOS,iPad,iPhone,Objective-c
- ios开发-c语言之其他数据类型的学
- C# TCP服务端 可以接收其他语言或平台发送的TCP消息
- C# TCP服务端 可以接收其他语言或平台发送的TCP消息
- iOS开发 - Xcode如何更换iPhone或iPad模拟器的类型
- js 判断当前设备(Android IOS)和版本号或其他对应设备信息
- ios 关于如何获取iphone或iPad的ip地址
- 使用eclipse插件批量将Java源代码文件的编码从GBK(或其他编码)转为UTF-8
- 使用useBean或其他方式
- iOS 8 用户可以使用 iPhone 或 iPad 的 mic 识别歌曲名称和歌手信息
- 超链接(或其他get请求),中文参数的处理
- 通过select改变其他元素的属性或子节点
- 通过select改变其他元素的属性或子节点
- 提供一个MTK在LCD上直接输入汉字或其他语言字串的函数
- The Tomcat server configuration at\...详细步骤
- 一次性把新增的文件 svn add
- http 访问网络 返回json 解析json
- hdu 4630 树状数组+离线操作+GCD
- android ndk not support pthread_cancel
- 从 iOS,Objective-C, IPhone, iPad, Android, Java, Node.js 或其他平台,或通过其他开发语言,使用WS-Trust请求一个ADFS的令牌
- 何时会发生db file sequential read等待事件?
- servlet登录例子之思考
- Linux unexpected inconsistency; run fsck manually 磁盘没有成功挂载
- 基数排序
- 再见了我的实习
- eclipse常用快捷键
- Java中String.getBytes()
- iOS多线程GCD