ios – CFHTTPMessageAddAuthentication无法向请求添加身份验证数据

ios – CFHTTPMessageAddAuthentication无法向请求添加身份验证数据,第1张

概述我正在尝试扩展 SocketRocket库的功能.我想添加身份验证功能. 由于此库使用CFNetwork CFHTTPMessage* API进行HTTP功能(需要启动Web套接字连接),我正在尝试使用此API来提供身份验证. 有完全匹配的功能:CFHTTPMessageAddAuthentication,但它不能像我期望的那样工作(据我所知documentation). 以下是显示问题的代码示例 我正在尝试扩展 SocketRocket库的功能.我想添加身份验证功能.

由于此库使用CFNetwork CFHTTPMessage* API进行http功能(需要启动Web套接字连接),我正在尝试使用此API来提供身份验证.
有完全匹配的功能:CFhttpMessageAddAuthentication,但它不能像我期望的那样工作(据我所知documentation).

以下是显示问题的代码示例:

- (CFhttpMessageRef)createAuthenticationHandShakeRequest: (CFhttpMessageRef)chalengeMessage {    CFhttpMessageRef request = [self createHandshakeRequest];    BOol result = CFhttpMessageAddAuthentication(request,chalengeMessage,(__brIDge CFStringRef)self.credentials.user,(__brIDge CFStringRef)self.credentials.password,kcfhttpAuthenticationSchemeDigest,/* I've also trIEd NulL for use strongest supplIEd authentication */                                                 NO);    if (!result) {        Nsstring *chalengeDescription = [[Nsstring alloc] initWithData: CFBrIDgingrelease(CFhttpMessagecopySerializedMessage(chalengeMessage))                                                              enCoding: NSUTF8StringEnCoding];        Nsstring  *requestDescription = [[Nsstring alloc] initWithData: CFBrIDgingrelease(CFhttpMessagecopySerializedMessage(request))                                                              enCoding: NSUTF8StringEnCoding];        SRFastLog(@"Failed to add authentication data `%@` to a request:\n%@After a chalenge:\n%@",self.credentials,requestDescription,chalengeDescription);    }    return request;}

requestDescription内容是:

GET /digest-auth/auth/user/passwd http/1.1Host: httpbin.orgSec-WebSocket-Version: 13Upgrade: websocketSec-WebSocket-Key: 3P5YiQDt+g/wgxHe71Af5Q==Connection: UpgradeOrigin: http://httpbin.org/

chalengeDescription包含:

http/1.1 401 UNAUTHORIZEDServer: NginxContent-Type: text/HTML; charset=utf-8Set-cookie: fake=fake_valueAccess-Control-Allow-Origin: http://httpbin.org/Access-Control-Allow-Credentials: trueDate: Mon,29 Jun 2015 12:21:33 GMTProxy-Support: Session-Based-AuthenticationWww-Authenticate: Digest nonce="0c7479b412e665b8685bea67580cf391",opaque="4ac236a2cec0fc3b07ef4d628a4aa679",realm="me@kennethreitz.com",qop=authContent-Length: 0Connection: keep-alive

用户和密码值有效(“user”“passwd”).

为什么CFhttpMessageAddAuthentication返回NO?不知道问题是什么.我也尝试使用凭据更新空请求,但没有运气.

我已经使用http://httpbin.org/进行测试(在此步骤中,Web套接字的功能无关紧要).

请注意,使用过的代码不会使用(并且永远不会)NSURLRequst或NSURLSession或NSURLConnection /

我尝试使用不同的函数:CFhttpAuthenticationCreateFromresponse和CFhttpMessageApplyCredentials,结果相同.
至少CFhttpMessageApplyCredentials以CFStreamError的形式返回一些错误信息.问题是这个错误信息是无用的:error.domain = 4,error.error = -1000这些值没有记录在任何地方.
唯一记录的值如下所示:

typedef CF_ENUM(CFIndex,CFStreamErrorDomain) {    kcfStreamErrorDomainCustom = -1L,/* custom to the kind of stream in question */    kcfStreamErrorDomainPOSIX = 1,/* POSIX errno; interpret using <sys/errno.h> */    kcfStreamErrorDomainMacOsstatus      /* Osstatus type from Carbon APIs; interpret using <MacTypes.h> */};

CFhttpAuthenticationCreateFromresponse返回无效对象,该描述返回:

<CFhttpAuthentication 0x108810450>{state = Failed; scheme = <undecIDed>,forProxy = false}

我在文档中发现了这些值的含义:domain = kcfStreamErrorDomainhttp,error = kcfStreamErrorhttpAuthenticationTypeUnsupported(感谢@JensAlfke我在你的评论之前找到了它).为什么它不受支持?文档声称支持摘要有一个常量kcfhttpAuthenticationSchemeDigest,CFhttpMessageAddAuthentication接受并期望它!

我已经挖掘了source code of CFNetwork authentication并试图找出问题所在.

我必须犯一些错误,因为这个简单的tast应用程序也会失败:

#import <Foundation/Foundation.h>#import <CFNetwork/CFNetwork.h>static Nsstring * const khttpAuthheadername = @"WWW-Authenticate";static Nsstring * const khttpDigestChallengeExample1 = @"Digest realm=\"testrealm@host.com\","    "qop=\"auth,auth-int\","    "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","    "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";static Nsstring * const khttpDigestChallengeExample2 = @"Digest nonce=\"b6921981b6437a4f138ba7d631bcda37\","    "opaque=\"3de7d2bd5708ac88904acbacbbebc4a2\","    "realm=\"me@kennethreitz.com\","    "qop=auth";static Nsstring * const khttpBasicChallengeExample1 = @"Basic realm=\"Fake Realm\"";#define RETURN_STRING_IF_CONSTANT(a,x) if ((a) == (x)) return @ #xNsstring *NsstringFromCFErrorDomain(CFIndex domain) {    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainhttp);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainFTP);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainSSL);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainSystemConfiguration);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainSOCKS);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainPOSIX);    RETURN_STRING_IF_CONSTANT(domain,kcfStreamErrorDomainMacOsstatus);    return [Nsstring stringWithFormat: @"UnkNownDomain=%ld",domain];}Nsstring *NsstringFromCFErrorError(SInt32 error) {    RETURN_STRING_IF_CONSTANT(error,kcfStreamErrorhttpAuthenticationTypeUnsupported);    RETURN_STRING_IF_CONSTANT(error,kcfStreamErrorhttpAuthenticationBadUsername);    RETURN_STRING_IF_CONSTANT(error,kcfStreamErrorhttpAuthenticationBadPassword);    return [Nsstring stringWithFormat: @"UnkNownError=%d",(int)error];}Nsstring *NsstringFromCFhttpMessage(CFhttpMessageRef message) {    return [[Nsstring alloc] initWithData: CFBrIDgingrelease(CFhttpMessagecopySerializedMessage(message))                                 enCoding: NSUTF8StringEnCoding];}voID testAuthenticationheader(Nsstring *authenticatiohheader) {    CFhttpMessageRef response = CFhttpMessageCreateResponse(kcfAllocatorDefault,401,NulL,kcfhttpVersion1_1);    CFautorelease(response);    CFhttpMessageSetheaderFIEldValue(response,(__brIDge CFStringRef)khttpAuthheadername,(__brIDge CFStringRef)authenticatiohheader);    CFhttpAuthenticationRef authData = CFhttpAuthenticationCreateFromresponse(kcfAllocatorDefault,response);    CFautorelease(authData);    CFStreamError error;    BOol valIDAuthData = CFhttpAuthenticationIsValID(authData,&error);    NSLog(@"testing header value: %@\n%@authData are %@   error.domain=%@  error.error=%@\n\n",authenticatiohheader,NsstringFromCFhttpMessage(response),valIDAuthData?@"ValID":@"INVALID",NsstringFromCFErrorDomain(error.domain),NsstringFromCFErrorError(error.error));}int main(int argc,const char * argv[]) {    @autoreleasepool {        testAuthenticationheader(khttpDigestChallengeExample1);        testAuthenticationheader(khttpDigestChallengeExample2);        testAuthenticationheader(khttpBasicChallengeExample1);    }    return 0;}

日志显示:

2015-07-01 16:33:57.659 cfauthtest[24742:600143] testing header value: Digest realm="testrealm@host.com",qop="auth,auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"http/1.1 401 UnauthorizedWww-Authenticate: Digest realm="testrealm@host.com",opaque="5ccc069c403ebaf9f0171e9517f40e41"authData are INVALID   error.domain=kcfStreamErrorDomainhttp  error.error=kcfStreamErrorhttpAuthenticationTypeUnsupported2015-07-01 16:33:57.660 cfauthtest[24742:600143] testing header value: Digest nonce="b6921981b6437a4f138ba7d631bcda37",opaque="3de7d2bd5708ac88904acbacbbebc4a2",qop=authhttp/1.1 401 UnauthorizedWww-Authenticate: Digest nonce="b6921981b6437a4f138ba7d631bcda37",qop=authauthData are INVALID   error.domain=kcfStreamErrorDomainhttp  error.error=kcfStreamErrorhttpAuthenticationTypeUnsupported2015-07-01 16:33:57.660 cfauthtest[24742:600143] testing header value: Basic realm="Fake Realm"http/1.1 401 UnauthorizedWww-Authenticate: Basic realm="Fake Realm"authData are INVALID   error.domain=kcfStreamErrorDomainhttp  error.error=kcfStreamErrorhttpAuthenticationTypeUnsupported

在我自己的回答后编辑:

替代解决方案

其他可能的解决方案是手动解析WWW-Authenticate响应头并进行它并为新请求生成Authorization头.

是否有一些我可以在商业应用程序中使用的简单库或示例代码(只有这个)?我能做到这一点,但这需要宝贵的时间.赏金仍然可用:).

解决方法 回答自己的问题:(

Apple CFNetwork API很糟糕

问题是CFhttpMessageRef中的响应具有隐藏的属性URL.
您可以阅读它:CFhttpMessagecopyRequestURL未设置它,并且需要从CFhttpMessageRef正确创建身份验证对象.如果URL属性为空,则身份验证将失败.

那么为什么有些案例的响应与身份验证质询包含URL在其他情况下不是?
此工作响应来自CFReadStreamCreateForhttpRequest创建的CFReadStreamRef作为此流的属性. Here is crappy example.因此,由于SocketRocket不使用CFReadStreamCreateForhttpRequest,这是一个无法简单克服的大问题.

令人遗憾的是,CFhttpMessageAddAuthentication可以从请求修改的URL获取此URL,如果在响应中找不到它.

解决方法

在这个问题上有完美的解决方法!但它涉及使用私有API(所以很可能它不会通过Apple审查).以下是完整的示例代码及其解决方法(与问题相同,但应用此解决方法),解决方法只需两行:公开私有API并使用它.

#import <Foundation/Foundation.h>#import <CFNetwork/CFNetwork.h>static Nsstring * const khttpAuthheadername = @"WWW-Authenticate";static Nsstring * const khttpDigestChallengeExample1 = @"Digest realm=\"testrealm@host.com\",(int)error];}Nsstring *NsstringFromCFhttpMessage(CFhttpMessageRef message) {    return [[Nsstring alloc] initWithData: CFBrIDgingrelease(CFhttpMessagecopySerializedMessage(message))                                 enCoding: NSUTF8StringEnCoding];}// exposing private API for workaroundextern voID _CFhttpMessageSetResponseURL(CFhttpMessageRef,CFURLRef);voID testAuthenticationheader(Nsstring *authenticatiohheader) {    CFhttpMessageRef response = CFhttpMessageCreateResponse(kcfAllocatorDefault,kcfhttpVersion1_1);    CFautorelease(response);    // workaround: use of private API    _CFhttpMessageSetResponseURL(response,(__brIDge CFURLRef)[NSURL URLWithString: @"http://some.test.url.com/"]);    CFhttpMessageSetheaderFIEldValue(response,const char * argv[]) {    @autoreleasepool {        testAuthenticationheader(khttpDigestChallengeExample1);        testAuthenticationheader(khttpDigestChallengeExample2);        testAuthenticationheader(khttpBasicChallengeExample1);    }    return 0;}

日志结果如下:

2015-07-03 11:47:02.849 cfauthtest[42766:934054] testing header value: Digest realm="testrealm@host.com",opaque="5ccc069c403ebaf9f0171e9517f40e41"authData are ValID   error.domain=UnkNownDomain=0  error.error=UnkNownError=02015-07-03 11:47:02.852 cfauthtest[42766:934054] testing header value: Digest nonce="b6921981b6437a4f138ba7d631bcda37",qop=authauthData are ValID   error.domain=UnkNownDomain=0  error.error=UnkNownError=02015-07-03 11:47:02.852 cfauthtest[42766:934054] testing header value: Basic realm="Fake Realm"http/1.1 401 UnauthorizedWww-Authenticate: Basic realm="Fake Realm"authData are ValID   error.domain=UnkNownDomain=0  error.error=UnkNownError=0

所以解决方法有效.

我将继续寻找仅使用公共API的其他解决方法.至少现在我知道问题是什么.

总结

以上是内存溢出为你收集整理的ios – CFHTTPMessageAddAuthentication无法向请求添加身份验证数据全部内容,希望文章能够帮你解决ios – CFHTTPMessageAddAuthentication无法向请求添加身份验证数据所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1105149.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-28
下一篇 2022-05-28

发表评论

登录后才能评论

评论列表(0条)

保存