天道酬勤,学无止境

How to parse values from Www-Authenticate

The value that I need to parse is part of a Www-Authenticate HTTP response header:

realm="https://auth.docker.io/token",service="registry.docker.io",scope="registry:catalog:*"

I would like to get a dictionary (or similar) with the following values:

{ "realm", "https://auth.docker.io/token" },
{ "service", "registry.docker.io" },
{ "scope", "registry:catalog:*"},

Is there some utility built into .NET that will parse this?

This is how I'm getting the value. In making a call to a Web API service, I am getting an Unauthorized response (this is expected):

var httpClient = new HttpClient();

//This is a public url
var response = await httpClient.GetAsync("https://registry-1.docker.io/v2/_catalog")

// This is the value that needs to be parsed
string parameter = response.Headers.WwwAuthenticate.FirstOrDefault().Parameter; 

Things I've tried / looked at:

  • Regular Expressions (painful and feels like overkill)
  • Manual parsing (statefully walking through the string. This strikes me as fragile and painful in having to look for escaped characters
  • Using string.Split. Is this safe? What if there are commas in the quoted values?
标签

评论

Using the schema defined in RFC6750 and RFC2616, a slightly more precise parser implementation is included below. This parser takes into account the possibility that strings might contain =, ,, and/or escaped ".

internal class AuthParamParser
{
  private string _buffer;
  private int _i;

  private AuthParamParser(string param)
  {
    _buffer = param;
    _i = 0;
  }

  public static Dictionary<string, string> Parse(string param)
  {
    var state = new AuthParamParser(param);
    var result = new Dictionary<string, string>();
    var token = state.ReadToken();
    while (!string.IsNullOrEmpty(token))
    {
      if (!state.ReadDelim('='))
        return result;
      result.Add(token, state.ReadString());
      if (!state.ReadDelim(','))
        return result;
      token = state.ReadToken();
    }
    return result;
  }

  private string ReadToken()
  {
    var start = _i;
    while (_i < _buffer.Length && ValidTokenChar(_buffer[_i]))
      _i++;
    return _buffer.Substring(start, _i - start);
  }

  private bool ReadDelim(char ch)
  {
    while (_i < _buffer.Length && char.IsWhiteSpace(_buffer[_i]))
      _i++;
    if (_i >= _buffer.Length || _buffer[_i] != ch)
      return false;
    _i++;
    while (_i < _buffer.Length && char.IsWhiteSpace(_buffer[_i]))
      _i++;
    return true;
  }

  private string ReadString()
  {
    if (_i < _buffer.Length && _buffer[_i] == '"')
    {
      var buffer = new StringBuilder();
      _i++;
      while (_i < _buffer.Length)
      {
        if (_buffer[_i] == '\\' && (_i + 1) < _buffer.Length)
        {
          _i++;
          buffer.Append(_buffer[_i]);
          _i++;
        }
        else if (_buffer[_i] == '"')
        {
          _i++;
          return buffer.ToString();
        }
        else
        {
          buffer.Append(_buffer[_i]);
          _i++;
        }
      }
      return buffer.ToString();
    }
    else
    {
      return ReadToken();
    }
  }

  private bool ValidTokenChar(char ch)
  {
    if (ch < 32)
      return false;
    if (ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '@'
      || ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"'
      || ch == '/' || ch == '[' || ch == ']' || ch == '?' || ch == '='
      || ch == '{' || ch == '}' || ch == 127 || ch == ' ' || ch == '\t')
      return false;
    return true;
  }
}

From the answer that Forty3 directed me to, I came up with the following:

public static class AuthenticateParser
{
    public static IDictionary<string, string> Parse(string value)
    {
        //https://stackoverflow.com/questions/45516717/extracting-and-parsing-the-www-authenticate-header-from-httpresponsemessage-in/45516809#45516809
        string[] commaSplit = value.Split(", ".ToCharArray());

        return commaSplit
            .ToDictionary(GetKey, GetValue);
    }

    private static string GetKey(string pair)
    {
        int equalPos = pair.IndexOf("=");

        if (equalPos < 1)
            throw new FormatException("No '=' found.");

        return  pair.Substring(0, equalPos);
    }

    private static string GetValue(string pair)
    {
        int equalPos = pair.IndexOf("=");

        if (equalPos < 1)
            throw new FormatException("No '=' found.");

        string value = pair.Substring(equalPos + 1).Trim();

        //Trim quotes
        if (value.StartsWith("\"") && value.EndsWith("\""))
        {
            value = value.Substring(1, value.Length - 2);
        }

        return value;
    }
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Extracting and Parsing the WWW-Authenticate header from HttpResponseMessage in .NET
    I'm building an app using Azure AD to call the Microsoft Graph. In certain requests that require elevated access, the graph is issuing an HTTP 403 error with a special claims parameter inside the WWW-Authenticate header I need to use in a subsequent request. In .NET, how can I extract the WWW-Authenticate header produced by an API in response to a Forbidden (HTTP 403) from the HttpResponseMessage class? Moreover, what's the best way to parse this header to extract out certain pieces of data? For instance, the response is comma separated, but also contains commas inside the chunk of data I need
  • 多个方案的 WWW-Authenticate 的分隔符是什么?(What is the delimiter for WWW-Authenticate for multiple schemes?)
    问题 我已经通读了 RFC 2617,如果支持多种方案,则无法在那里或其他任何地方找到分隔符是什么。 例如,假设支持 Basic 和 Digest。 我知道它可能会以这种方式出现: HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic WWW-Authenticate: Digest 但我也读过,两者都可以列为一行,但没有人展示过示例或描述要使用的分隔符。 我已经看到警告可以在单个方案中使用逗号: HTTP/1.1 401 Unauthorized WWW-Authenticate: Digest param1="foo", param2="bar" 我还读到,如果在一个方案中使用逗号,则其他方案必须放在单独的行上。 所以我想在上面的例子中,如果我们添加 Basic 它会是这样的: HTTP/1.1 401 Unauthorized WWW-Authenticate: Digest param1="foo", param2="bar" WWW-Authenticate: Basic 这很简单。 但现在假设你只有一行 HTTP/1.1 401 Unauthorized WWW-Authenticate: Scheme stuff, morestuff, more stuff 那是哪个? 这是一个以逗号分隔的方案列表
  • 使用Node and Express 4的基本HTTP身份验证(Basic HTTP authentication with Node and Express 4)
    问题 使用Express v3实施基本的HTTP身份验证似乎很简单: app.use(express.basicAuth('username', 'password')); 不过,第4版(我使用的是4.2)删除了basicAuth中间件,所以我有些basicAuth 。 我有以下代码,但是它不会导致浏览器提示用户输入凭据,这就是我想要的(以及我想像的旧方法所做的): app.use(function(req, res, next) { var user = auth(req); if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') { res.writeHead(401, 'Access invalid for user', {'Content-Type' : 'text/plain'}); res.end('Invalid credentials'); } else { next(); } }); 回答1 带有JavaScript (ES6)的简单基本身份验证 app.use((req, res, next) => { // ----------------------------------------------------------------------
  • java.io.IOException:找不到身份验证挑战(java.io.IOException : No authentication challenges found)
    问题 我是android的新手,这是我在android上的第一个项目。 我为“身份验证”问题苦苦挣扎超过一天。 我尝试了几种选择,但没有一个起作用。 基本上,我想调用REST API并获得响应。 我确信API不会出现问题,因为我在另一个iOS应用程序中使用了相同的API。 我通过授权标头,但仍显示身份验证,未显示任何消息。 我发现很少有与此相关的关于stackoverflow的问题,但是其中一些没有用,有些对我来说没有意义。 我收到状态码401 。 我知道这意味着没有通过身份验证,或者如果通过了身份验证,那么它们是错误的。 在这里,我确信我通过的是正确的。 下面是我的代码: try { url = new URL(baseUrl); } catch (MalformedURLException me) { Log.e(TAG, "URL could not be parsed. URL : " + baseUrl + ". Line : " + getLineNumber(), me); me.printStackTrace(); } try { urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod(method); urlConnection
  • CFHTTPMessageAddAuthentication 无法向请求添加身份验证数据(CFHTTPMessageAddAuthentication fails to add authentication data to request)
    问题 我正在尝试扩展 SocketRocket 库的功能。 我想添加身份验证功能。 由于该库使用 CFNetwork CFHTTPMessage* API 来实现 HTTP 功能(需要启动 Web 套接字连接),因此我正在尝试利用此 API 来提供身份验证。 有完美匹配的功能: CFHTTPMessageAddAuthentication ,但它不像我期望的那样工作(据我了解文档)。 这是显示问题的代码示例: - (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
  • 如何删除不需要的 WWW-Authenticate 标头(How to remove unwanted WWW-Authenticate headers)
    问题 从 MVC 应用程序中,我正在根据对这个 SO 问题的回答获取带有身份验证的 iCal 订阅: 使用身份验证在 ASPNET MVC 中提供 iCalendar 文件 iCal 流是使用 DDay.iCal 库从数据库中的事件动态创建的。 此解决方案在本地开发服务器上运行良好:OSX 日历和 Outlook 都可以从应用程序订阅和接收更新。 但是,在我的 Web 主机上的共享服务器上,日历和 Outlook 的身份验证均失败。 也就是说,他们都在(正确的)失败后不断向我询问用户和密码。 编辑:如果我将浏览器指向日历 URL,它也会无法通过身份验证。 编辑:变得更奇怪——Firefox 验证并获取 iCal 文件。 Safari、Chrome 和 IE 验证失败。 如果我使用相同的凭据将 curl 指向日历 URL,我就成功了(即我获得了所需的 iCal 文件)。 当然,可以使用相同的凭据登录到 MVC 应用程序。 编辑 - 我想我知道发生了什么,但我不知道如何解决它。 在我的OnAuthorization()我只添加了WWW-Authentication Basic但使用 Fiddler 我可以看到提供了三种类型的身份验证: HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Secure Calendar"
  • CFHTTPMessageAddAuthentication fails to add authentication data to request
    I'm trying to extend functionality of SocketRocket library. I want to add authentication feature. Since this library is using CFNetwork CFHTTPMessage* API for HTTP functionality (needed to start web socket connection) I'm trying to utilize this API to provide authentication. There is perfectly matching function for that: CFHTTPMessageAddAuthentication, but it doesn't work as I'm expecting (as I understand documentation). Here is sample of code showing the problem: - (CFHTTPMessageRef)createAuthenticationHandShakeRequest: (CFHTTPMessageRef)chalengeMessage { CFHTTPMessageRef request = [self
  • RESTful HTTP API 中的授权,401 WWW-Authenticate(Authorization in RESTful HTTP API, 401 WWW-Authenticate)
    问题 我正在创建一个 RESTful 服务来向 Web 应用程序提供数据。 我有两个相关的问题。 1、如何处理未经授权的请求? 我打算使用以下代码响应请求: 资源是否打开并找到? 200 正常您是否需要通过身份验证才能访问资源? 401 未授权您不能访问某一类资源吗? 403 禁地您是否有权访问某类资源,但不能访问该特定资源? 404 Not Found防止人们了解他们无权访问的资源的存在。 资源不存在吗? 404 未找到 这是 RESTful 服务的推荐行为方式吗? 2. 401 响应应该提供什么WWW-Authenticate标头? 我在维基百科上读到(可能不是最准确的资源,但它对我有用) 401 响应必须包含WWW-Authenticate标头,但是在进一步搜索时,我无法真正找到任何说明此值的含义和含义的资源它应该是。 我发现了几个关于这个标题的 SO 问题和论坛主题,它们似乎都与 OAuth 相关,建议不要使用 401 状态代码,或者说你可以做一些事情。 此标头应包含的正确值是什么? 回答1 回答您的问题: 如何处理未经授权的请求? 您描述的方式几乎是 RESTful 服务的推荐方式。 据我所知,这绝对没有错。 401 响应应提供什么 WWW-Authenticate 标头? 通常, WWW-Authenticate标头告诉客户端服务器将接受哪种身份验证。
  • 使用HttpURLConnection在Android中进行摘要式身份验证(Digest authentication in Android using HttpURLConnection)
    问题 正如所有问题已经说过的那样,我正在尝试在android中进行摘要身份验证。 到目前为止,我一直使用DefaultHttpClient及其身份验证方法(使用UsernamePasswordCredentials等),但是自Android 5起不推荐使用,并将在Android 6中将其删除。 所以我要从DefaultHttpClient切换到HttpUrlConnection 。 现在,我正在尝试实现摘要身份验证,该身份验证应如此处所述非常简单地工作: Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); 但是由于某种原因,从未调用过getPasswordAuthentication 。 在搜索此问题的过程中,我发现了不同的帖子,说android中的HttpUrlConnection不支持摘要身份验证,但是这些帖子来自2010-2012,所以我不确定这是否仍然正确。 另外,我们HttpUrlConnection台式机Java应用程序中使用带有摘要身份验证的HttpUrlConnection
  • Getting “x-amzn-Remapped-WWW-Authenticate instead of WWW-Authenticate and jetty client not able to recognise
    AWS API gateway remaps WWW-Authenticate header as x-amazn-remapped-WWW-Authenticate. Our customers use java jetty client and jetty client is failing since jetty client is looking for WWW-Authenticate header How to send WWW-Authenticate from AWS API gateway Any fix on the Jetty client? I tried to use gateway response on 1. AWS API gateway response - to handle 400 2. Integration Response - to handle 400 requests and then set the WWW-authenticate header #set($inputRoot = $input.path('$')) $input.json("$") #if($inputRoot.toString().contains("error")) #set($context.responseOverride.status = 400)
  • node.js客户端中的Windows集成身份验证(Windows Integrated Authentication in node.js Client)
    问题 当使用node.js作为客户端时,是否可以使用Windows集成身份验证连接到服务器(例如,连接到IIS时)? 我对此的搜索仅显示将node.js用作服务器的结果。 回答1 2015更新:现在有一些模块实现了Windows集成的身份验证。 node-sspi使用SSPI(Windows安全API)来处理服务器端的事务,但不执行客户端身份验证。 有几种客户端实现,例如http-ntlm,但是由于需要用户密码,因此它们并未真正集成-它们不使用SSPI进行透明身份验证。 2019更新:似乎可以使用kerberos库通过SSPI进行真正的Windows集成的HTTP身份验证(即,使用节点进程的令牌进行透明身份验证)。 请参阅kerberos-agent。 显然,这使用的是Kerberos,而不是NTLM / Negotiate,因此,根据您的实际情况,此方法可能有效也可能无效。 “ Windows集成身份验证”是所谓的NTLM身份验证。 现在,当您从IIS收到带有包含NTLM的WWW-Authenticate标头的HTTP 401时,就可以实现NTLM身份验证协议。 引用本文档中有关NTLM身份验证协议的内容: 客户端从服务器请求受保护的资源: GET /index.html HTTP/1.1 服务器以401状态响应,指示客户端必须进行身份验证。 NTLM通过WWW
  • Authorization in RESTful HTTP API, 401 WWW-Authenticate
    I'm creating a RESTful service to provide data to a web application. I have two related questions about this. 1. How to deal with unauthorized requests? I'm intending to respond to requests with the following codes: Is the resource open and found? 200 OK Do you need to be authenticated to access the resources? 401 Unauthorized Don't you have access to a category of resources? 403 Forbidden Do you have access to a category of resources, but not to this specific resource? 404 Not Found to prevent people from getting to know the existance of a resource they do not have access to. Doesn't the
  • HTTP 401-什么是适当的WWW-Authenticate标头值?(HTTP 401 - what's an appropriate WWW-Authenticate header value?)
    问题 目前我正在处理的应用程序具有会话超时值。 如果用户的交互时间不超过此值,则他们尝试加载的下一页将被提示登录。 发出的所有请求都通过此机制进行路由,该机制包括AJAX调用。 最初,我们在登录页面上发送了200标头,这引入了AJAX的一些问题,因为如果发送200响应,则代码将运行,并且从这些RPC调用返回的大多数数据都是JSON或经过评估的原始JavaScript(请勿问:|)。 我建议使用401更好,因为我们的JSON解析器不会尝试使用HTML登录页面。 但是,在阅读规范时,我注意到还必须发送WWW-Authenticate字段。 这个领域有什么好的价值? Application Login就足够了吗? 回答1 当指示HTTP基本身份验证时,我们返回类似以下内容的内容: WWW-Authenticate: Basic realm="myRealm" Basic是方案,其余部分很大程度上取决于该方案。 在这种情况下,领域仅向浏览器提供一个文字,当提示用户ID和密码时,该文字可以显示给用户。 您显然没有使用Basic,但是由于使用Basic Auth时会话没有到期的意义。 我假设您正在使用某种形式的基于表单的身份验证。 从回忆来看,Windows挑战响应使用了不同的方案和不同的参数。 诀窍在于,由浏览器决定它支持什么方案以及如何响应它们。 我的直觉是,如果您使用基于表单的身份验证
  • OAuth token submitted with the request can not be parsed
    I'm trying to implement a client that imports the events that a user has in Office 365 so that I can easily display them in the company's application. I managed to get the user to authenticate with his / her Office 365 account and to approve my application and to also get an AccessToken, but when I try to use the token to retrieve the events from the API, I get a 401 HTTP error code, no body and in the headers I have this: Content-Length →0 Date →Thu, 17 Mar 2016 08:56:00 GMT Server →Microsoft-IIS/8.0 WWW-Authenticate →Bearer client_id="00000002-0000-0ff1-ce00-000000000000", trusted_issuers=
  • java.io.IOException:ICS 4.0.3中收到的身份验证质询为空(java.io.IOException: Received authentication challenge is null in ICS 4.0.3)
    问题 我正在尝试从服务器注销。 但是,此异常返回“ 0”响应代码。 我正在使用GET动词来做到这一点。 LogCat 10-17 14:54:13.261: W/System.err(868): java.io.IOException: Received authentication challenge is null 10-17 14:54:13.284: W/System.err(868): at libcore.net.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:397) 10-17 14:54:13.284: W/System.err(868): at libcore.net.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:345) 10-17 14:54:13.304: W/System.err(868): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:276) 10-17 14:54:13.324: W/System.err(868): at
  • 应该使用什么http状态代码来告诉客户端会话已超时?(What http status code is supposed to be used to tell the client the session has timed out?)
    问题 在一个网页中,它使用YUI连接管理器/数据源将AJAX请求发送到服务器,如果会话(其中包含有关用户是否已通过身份验证的信息)已经超时,则那些只能通过身份验证查看的ajax响应用户应返回一个http状态代码,告诉客户端会话已超时,然后客户端要么将其重定向到登录页面,要么询问他是否要扩展会话。 我的问题是,在这种情况下,哪种HTTP状态代码最适合告诉客户端会话已超时? Wiki的HTTP状态代码列表 回答1 我所能建议的最好是带有WWW-Authenticate标头的HTTP 401状态代码。 403请求的问题在于RFC 2616指出“授权无济于事,不应重复该请求。” (即,无论您是否通过身份验证,永远都不会访问该资源)。 401请求的问题是它指出它们“必须包括WWW-Authenticate标头字段”。 正如有人指出的那样,在WWW-Authenticate标头中使用自定义值似乎没有违反规范。 我看不到任何在RFC 2617中为什么将HTTP 401状态与自定义WWW-Authenticate标头结合在一起的原因,这是不可行的: WWW-Authenticate: MyAuthScheme realm="http://example.com" oAuth规范实际上似乎就是这样做的,因为他们建议这样做(尽管在我看来,他们对RFC的解释很奇怪): WWW-Authenticate
  • HTTP 401 - what's an appropriate WWW-Authenticate header value?
    The application I'm working on at the moment has a session timeout value. If the user hasn't interacted for longer than this value, the next page they try to load, they will be prompted to log in. All requests made are routed through this mechanism, which includes AJAX calls. Originally we were sending a 200 header with the login page, which introduces some problems with AJAX since code is run if a 200 response is sent, and most data sent back from these RPC calls is JSON or raw JavaScript that gets evaluated (don't ask :|). I've suggested that a 401 is better, since our JSON parser won't try
  • How to remove unwanted WWW-Authenticate headers
    From an MVC app, I'm sourcing an iCal subscription with authentication following the answer to this SO question: Serving an iCalendar file in ASPNET MVC with authentication The iCal stream is being created dynamically from events in the DB using the DDay.iCal library. This solution works fine on the local development server: both OSX Calendar and Outlook can subscribe to and receive updates from the app. However, on the shared server at my web host, the authentication fails for both Calendar and Outlook. That is, they both keep asking me for user & password after the (correct) ones fail. EDIT
  • UCWA Lync 身份验证 - 500 Web 票证无效(UCWA Lync authentication - 500 web ticket is invalid)
    问题 我正在尝试使用 Nodejs 为 Lync 创建一个简单的客户端。 基于 http://ucwa.lync.com/documentation/KeyTasks-CreateApplication 我做了这样的事情。 当我应该向 UCWA 注册我的应用程序时,它一直工作到最后一步 #9。 服务器响应代码 500 和愚蠢的解释 您要找的资源有问题,无法显示 和标题 x-ms-diagnostics': '28032;source="mysource";reason="网络票无效。"' var http = require('request-promise'); var lync = {}; lync.setup = function(email, password){ var self = this; var hostname = email.split('@'); this.username = email; //discover urls return http.get('http://lyncdiscover.'+hostname[1]) .then(function(d) { var parsed = JSON.parse(d); self.urls = { self: parsed._links.self.href, user: parsed._links.user
  • 确定 Web http 身份验证方法(determining web http authentication methods)
    问题 您如何确定 REST Web 服务是使用 Basic、Kerberos、NTLM 还是许多其他身份验证方法之一? 回答1 当您发送未经身份验证的请求时,该服务必须以“HTTP/1.1 401 未经授权”作为响应,并且该响应包含一个WWW-Authenticate标头,该标头指定了预期的身份验证方案( Basic 、 Digest )、安全领域和任何其他特定值(就像 Digets 的 nonce 一样)。 因此,如果服务器响应为: HTTP/1.0 401 Unauthorized WWW-Authenticate: Digest realm="example.com", qop="auth,auth-int", nonce="...", opaque="..." 它需要摘要式身份验证。 如果响应如下所示: HTTP/1.0 401 Unauthorized WWW-Authenticate: Basic realm="example.com" 然后它需要基本身份验证。 一些(较差的)实现的服务器/站点不能正确处理基本并直接响应 403 Forbidden 而不是首先挑战。 NTLM 类似于服务器响应 401 和值为NTLM的 WWW-Authenticate 标头,但没有官方公开规范,因为它是 Microsoft 专有的。 有各种逆向工程描述。 不幸的是,REST 没有提供