From 941a4a78d7dc11bbe60f82fbe2b9ecd940352570 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Wed, 28 Oct 2015 10:28:50 +0000 Subject: [PATCH] HttpUtils.pm: Authorization:Digest added (Forum #43043) git-svn-id: https://svn.fhem.de/fhem/trunk@9705 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/HttpUtils.pm | 82 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/fhem/FHEM/HttpUtils.pm b/fhem/FHEM/HttpUtils.pm index 38d67a940..b3b197c27 100644 --- a/fhem/FHEM/HttpUtils.pm +++ b/fhem/FHEM/HttpUtils.pm @@ -6,6 +6,7 @@ use strict; use warnings; use IO::Socket::INET; use MIME::Base64; +use Digest::MD5; use vars qw($SSL_ERROR); my %ext2MIMEType= qw{ @@ -131,7 +132,7 @@ HttpUtils_Connect($) } $hash->{path} = '/' unless defined($hash->{path}); $hash->{addr} = "$hash->{protocol}://$host:$port"; - $hash->{auth} = encode_base64("$user:$pwd","") if($authstring); + $hash->{auth} = "$user:$pwd" if($authstring); return HttpUtils_Connect2($hash) if($hash->{conn} && $hash->{keepalive}); @@ -251,7 +252,11 @@ HttpUtils_Connect2($) $hdr .= "Connection: keep-alive\r\n" if($hash->{keepalive}); $hdr .= "Connection: Close\r\n" if($httpVersion ne "1.0" && !$hash->{keepalive}); - $hdr .= "Authorization: Basic $hash->{auth}\r\n" if(defined($hash->{auth})); + + $hdr .= "Authorization: Basic ".encode_base64($hash->{auth})."\r\n" + if(defined($hash->{auth}) && + !($hash->{header} && + $hash->{header} =~ /^Authorization:\s*Digest/mi)); $hdr .= $hash->{header}."\r\n" if(defined($hash->{header})); if(defined($data)) { $hdr .= "Content-Length: ".length($data)."\r\n"; @@ -329,6 +334,56 @@ HttpUtils_DataComplete($) return 1; } +sub +HttpUtils_DigestHeader($$) +{ + my ($hash, $header) = @_; + my %digdata; + + while($header =~ /(\w+)="?([^"]+?)"?(?:,\s+|$)/gc) { + $digdata{$1} = $2; + } + + my ($ha1, $ha2, $response); + my ($user,$passwd) = split(/:/, $hash->{auth}, 2); + + if(exists($digdata{qop})) { + $digdata{nc} = "00000001"; + $digdata{cnonce} = md5_hex(rand.time); + } + $digdata{uri} = $hash->{path}; + $digdata{username} = $user; + + if(exists($digdata{algorithm}) && $digdata{algorithm} eq "MD5-sess") { + $ha1 = md5_hex(md5_hex($user.":".$digdata{realm}.":".$passwd). + ":".$digdata{nonce}.":".$digdata{cnonce}); + } else { + $ha1 = md5_hex($user.":".$digdata{realm}.":".$passwd); + } + + # forcing qop=auth as qop=auth-int is not implemented + $digdata{qop} = "auth" if($digdata{qop}); + my $method = $hash->{method}; + $method = ($hash->{data} ? "POST" : "GET") if( !$method ); + $ha2 = md5_hex($method.":".$hash->{path}); + + if(exists($digdata{qop}) && $digdata{qop} =~ /(auth-int|auth)/) { + $digdata{response} = md5_hex($ha1.":". + $digdata{nonce}.":". + $digdata{nc}.":". + $digdata{cnonce}.":". + $digdata{qop}.":". + $ha2); + } else { + $digdata{response} = md5_hex($ha1.":".$digdata{nonce}.":".$ha2) + } + + return "Authorization: Digest ". + join(", ", map(($_.'='.($_ ne "nc" ? '"' :''). + $digdata{$_}.($_ ne "nc" ? '"' :'')), keys(%digdata))); + +} + sub HttpUtils_ParseAnswer($$) { @@ -375,6 +430,29 @@ HttpUtils_ParseAnswer($$) } Log3 $hash,$hash->{loglevel}, "$hash->{displayurl}: HTTP response code $code"; $hash->{code} = $code; + + # if servers requests digest authentication + if($code==401 && defined($hash->{auth}) && + !($hash->{header} && $hash->{header} =~ /^Authorization:\s*Digest/mi) && + $hash->{httpheader} =~ /^WWW-Authenticate:\s*Digest\s*(.+?)\s*$/mi) { + + $hash->{header} .= "\r\n". + HttpUtils_DigestHeader($hash, $1) if($hash->{header}); + $hash->{header} = HttpUtils_DigestHeader($hash, $1) if(!$hash->{header}); + + # Request the URL with the Digest response + if($hash->{callback}) { + HttpUtils_NonblockingGet($hash); + return ("", "", 1); + } else { + return HttpUtils_BlockingGet($hash); + } + + } elsif($code==401 && defined($hash->{auth})) { + return ("$hash->{displayurl}: wrong authentication", "") + + } + if(($code==301 || $code==302 || $code==303) && !$hash->{ignoreredirects}) { # redirect if(++$hash->{redirects} > 5) {