Changeset 0d57cf36be8bb038c67fe862fa27dc5a03553f05

Show
Ignore:
Timestamp:
03/19/12 20:39:59 (3 years ago)
Author:
Philip Maddox <pmaddox@circonus.com>
git-committer:
Philip Maddox <pmaddox@circonus.com> 1332189599 -0400
git-parent:

[55a909658a1fb1434491caf0b50e9b25fc8ac095]

git-author:
Philip Maddox <pmaddox@circonus.com> 1332189599 -0400
Message:

Added functionality to to digest authorization into HTTPClient

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/modules-lua/noit/HttpClient.lua

    r1581bb9 r0d57cf3  
    215215end 
    216216 
     217function HttpClient:auth_digest(method, uri, user, pass, challenge) 
     218    local c = ', ' .. challenge 
     219    local nc = '00000001' 
     220    local function rand_string(t, l) 
     221        local n = table.getn(t) 
     222        local o = '' 
     223        while l > 0 do 
     224          o = o .. t[math.random(1,n)] 
     225          l = l - 1 
     226        end 
     227        return o 
     228    end 
     229    local cnonce = 
     230        rand_string({'a','b','c','d','e','f','g','h','i','j','k','l','m', 
     231                     'n','o','p','q','r','s','t','u','v','x','y','z','A', 
     232                     'B','C','D','E','F','G','H','I','J','K','L','M','N', 
     233                     'O','P','Q','R','S','T','U','V','W','X','Y','Z','0', 
     234                     '1','2','3','4','5','6','7','8','9'}, 8) 
     235    local p = {} 
     236    for k,v in string.gmatch(c, ',%s+(%a+)="([^"]+)"') do p[k] = v end 
     237    for k,v in string.gmatch(c, ',%s+(%a+)=([^",][^,]*)') do p[k] = v end 
     238 
     239    -- qop can be a list 
     240    for q in string.gmatch(p.qop, '([^,]+)') do 
     241        if q == "auth" then p.qop = "auth" end 
     242    end 
     243 
     244    -- calculate H(A1) 
     245    local ha1 = noit.md5_hex(user .. ':' .. p.realm .. ':' .. pass) 
     246    if string.lower(p.qop or '') == 'md5-sess' then 
     247        ha1 = noit.md5_hex(ha1 .. ':' .. p.nonce .. ':' .. cnonce) 
     248    end 
     249    -- calculate H(A2) 
     250    local ha2 = '' 
     251    if p.qop == "auth" or p.qop == nil then 
     252        ha2 = noit.md5_hex(method .. ':' .. uri) 
     253    else 
     254        -- we don't support auth-int 
     255        error("qop=" .. p.qop .. " is unsupported") 
     256    end 
     257    local resp = '' 
     258    if p.qop == "auth" then 
     259        resp = noit.md5_hex(ha1 .. ':' .. p.nonce .. ':' .. nc 
     260                                .. ':' .. cnonce .. ':' .. p.qop 
     261                                .. ':' .. ha2) 
     262    else 
     263        resp = noit.md5_hex(ha1 .. ':' .. p.nonce .. ':' .. ha2) 
     264    end 
     265    local o = {} 
     266    o.username = user 
     267    o.realm = p.realm 
     268    o.nonce = p.nonce 
     269    o.uri = uri 
     270    o.cnonce = cnonce 
     271    o.qop = p.qop 
     272    o.response = resp 
     273    o.algorithm = p.algorithm 
     274    if p.opaque then o.opaque = p.opaque end 
     275    local hdr = '' 
     276    for k,v in pairs(o) do 
     277      if hdr == '' then hdr = k .. '="' .. v .. '"' 
     278      else hdr = hdr .. ', ' .. k .. '="' .. v .. '"' end 
     279    end 
     280    hdr = hdr .. ', nc=' .. nc 
     281    return hdr 
     282end 
     283 
    217284return HttpClient 
  • src/modules-lua/noit/module/resmon.lua

    r1581bb9 r0d57cf3  
    202202    local read_limit = tonumber(check.config.read_limit) or nil 
    203203 
    204     local user = check.config.auth_user or nil 
    205     local pass = check.config.auth_password or nil 
    206     local encoded = nil 
    207     if (user ~= nil and pass ~= nil) then 
    208         encoded = noit.base64_encode(user .. ':' .. pass) 
    209     end 
    210  
    211204    -- assume the worst. 
    212205    check.bad() 
     
    234227    callbacks.consume = function (str) output = output .. str end 
    235228    callbacks.headers = function (t) hdrs_in = t end 
     229    
     230    -- perform the request 
     231    local headers = {} 
     232    headers.Host = host 
     233 
     234    if check.config.auth_method == "Basic" or 
     235        (check.config.auth_method == nil and 
     236            check.config.auth_user ~= nil and 
     237            check.config.auth_password ~= nil) then 
     238        local user = check.config.auth_user or nil 
     239        local pass = check.config.auth_password or nil 
     240        local encoded = nil 
     241        if (user ~= nil and pass ~= nil) then 
     242            encoded = noit.base64_encode(user .. ':' .. pass) 
     243            headers["Authorization"] = "Basic " .. encoded 
     244        end 
     245    elseif check.config.auth_method == "Digest" or 
     246           check.config.auth_method == "Auto" then 
     247 
     248        -- this is handled later as we need our challenge. 
     249        local client = HttpClient:new() 
     250        local rv, err = client:connect(check.target_ip, port, use_ssl) 
     251        if rv ~= 0 then 
     252            check.status(str or "unknown error") 
     253            return 
     254        end 
     255        local headers_firstpass = {} 
     256        for k,v in pairs(headers) do 
     257            headers_firstpass[k] = v 
     258        end 
     259        client:do_request("GET", uri, headers_firstpass) 
     260        client:get_response(read_limit) 
     261        if client.code ~= 401 or 
     262           client.headers["www-authenticate"] == nil then 
     263            check.status("expected digest challenge, got " .. client.code) 
     264            return 
     265        end 
     266        local user = check.config.auth_user or '' 
     267        local password = check.config.auth_password or '' 
     268        local ameth, challenge = 
     269            string.match(client.headers["www-authenticate"], '^(%S+)%s+(.+)$') 
     270        if check.config.auth_method == "Auto" and ameth == "Basic" then 
     271            local encoded = noit.base64_encode(user .. ':' .. password) 
     272            headers["Authorization"] = "Basic " .. encoded 
     273        elseif ameth == "Digest" then 
     274            headers["Authorization"] = 
     275                "Digest " .. client:auth_digest("GET", uri, 
     276                                         user, password, challenge) 
     277        else 
     278            check.status("Unexpected auth '" .. ameth .. "' in challenge") 
     279            return 
     280        end 
     281    elseif check.config.auth_method ~= nil then 
     282        check.status("Unknown auth method: " .. check.config.auth_method) 
     283        return 
     284    end 
     285 
    236286    local client = HttpClient:new(callbacks) 
    237287    local rv, err = client:connect(check.target_ip, port, use_ssl) 
    238     
    239288    if rv ~= 0 then 
    240289        check.status(err or "unknown error") 
     
    242291    end 
    243292 
    244     -- perform the request 
    245     local headers = {} 
    246     headers.Host = host 
    247     if encoded ~= nil then 
    248         headers["Authorization"] = "Basic " .. encoded 
    249     end 
    250293    client:do_request("GET", uri, headers) 
    251294    client:get_response(read_limit)