HTTPS/Authenticated

Revision as of 18:49, 7 December 2017 by PureFox (talk | contribs) (Added Kotlin)

The goal of this task is to demonstrate HTTPS requests with authentication. Implementations of this task should not use client certificates for this: that is the subject of another task.

Task
HTTPS/Authenticated
You are encouraged to solve this task according to the task description, using any language you may know.

AutoHotkey

Library: iweb
Library: COM

<lang AutoHotkey>iWeb_Init() pwb := iWeb_newGui(0, 0, 1000, 800) iWeb_nav(pwb, "http://www.facebook.com/login.php?ref=pf") iWeb_Term() iWeb_complete(pwb) inputbox, email, email inputbox, pass, password iWeb_setDomObj(pwb,"Email",email) iWeb_setDomObj(pwb,"pass",pass) iWeb_clickDomObj(pwb, "login") return

  1. Include iweb.ahk
  2. Include COM.ahk
  3. Include COMinvokeDeep.ahk</lang>

C

Library: libcurl

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include "curl/curl.h"

int main(void) {

       CURL *curl;
       char buffer[CURL_ERROR_SIZE];
       if ((curl = curl_easy_init()) != NULL) {
               curl_easy_setopt(curl, CURLOPT_URL, "https://user:password@secure.example.com/");
               curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
               curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);
               if (curl_easy_perform(curl) != CURLE_OK) {
                       fprintf(stderr, "%s\n", buffer);
                       return EXIT_FAILURE;
               }
               curl_easy_cleanup(curl);
       }
       return EXIT_SUCCESS;

}</lang>

C#

Works with: C sharp version 3.0

<lang csharp> using System; using System.Net;

class Program {

   static void Main(string[] args)
   {
       var client = new WebClient();
       // credentials of current user:
       client.Credentials = CredentialCache.DefaultCredentials;
       // or specify credentials manually:
       client.Credentials = new NetworkCredential("User", "Password");
       var data = client.DownloadString("https://example.com");
       Console.WriteLine(data);
   }

} </lang>

Clojure

Library: clj-http

<lang clojure>(clj-http.client/get "https://somedomain.com"

                    {:basic-auth ["user" "pass"]})</lang>

Delphi

<lang Delphi>program ShowHTTPSAuthenticated;

{$APPTYPE CONSOLE}

uses IdHttp, IdSSLOpenSSL;

var

 s: string;
 lHTTP: TIdHTTP;
 lIOHandler: TIdSSLIOHandlerSocketOpenSSL;

begin

 ReportMemoryLeaksOnShutdown := True;
 lHTTP := TIdHTTP.Create(nil);
 lIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
 try
   lHTTP.Request.Username := 'USERNAME';
   lHTTP.Request.Password := 'PASSWD';
   lHTTP.IOHandler := lIOHandler;
   lHTTP.HandleRedirects := True;
   s := lHTTP.Get('https://SomeSecureSite.net/');
   Writeln(s);
 finally
   lHTTP.Free;
   lIOHandler.Free;
 end;

end.</lang>

Go

The task solution is really the client program, but to test it I wrote a server and created a custom certificate. I won't describe the certificate, but this is the server: <lang go>package main

import (

   "encoding/base64"
   "io"
   "log"
   "net/http"
   "strings"

)

const userPass = "rosetta:code" const unauth = http.StatusUnauthorized

func hw(w http.ResponseWriter, req *http.Request) {

   auth := req.Header.Get("Authorization")
   if !strings.HasPrefix(auth, "Basic ") {
       log.Print("Invalid authorization:", auth)
       http.Error(w, http.StatusText(unauth), unauth)
       return
   }
   up, err := base64.StdEncoding.DecodeString(auth[6:])
   if err != nil {
       log.Print("authorization decode error:", err)
       http.Error(w, http.StatusText(unauth), unauth)
       return
   }
   if string(up) != userPass {
       log.Print("invalid username:password:", string(up))
       http.Error(w, http.StatusText(unauth), unauth)
       return
   }
   io.WriteString(w, "Goodbye, World!")

}

func main() {

   http.HandleFunc("/", hw)
   log.Fatal(http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil))

}</lang> It is a "Hello world" server, but over TLS and with basic authentication required on the Get. Errors are logged to aid client debugging.

The client: <lang go>package main

import (

   "crypto/tls"
   "crypto/x509"
   "fmt"
   "io/ioutil"
   "log"
   "net/http"

)

const (

   userid   = "rosetta"
   password = "code"

)

func main() {

   // Use custom certificate for testing.  Not exactly required by task.
   b, err := ioutil.ReadFile("cert.pem")
   if err != nil {
       log.Fatal(err)
   }
   pool := x509.NewCertPool()
   if ok := pool.AppendCertsFromPEM(b); !ok {
       log.Fatal("Failed to append cert")
   }
   tc := &tls.Config{RootCAs: pool}
   tr := &http.Transport{TLSClientConfig: tc}
   client := &http.Client{Transport: tr}
   req, err := http.NewRequest("GET", "https://127.0.0.1:8080", nil)
   if err != nil {
       log.Fatal(err)
   }
   // This one line implements the authentication required for the task.
   req.SetBasicAuth(userid, password)
   // Make request and show output.
   resp, err := client.Do(req)
   if err != nil {
       log.Fatal(err)
   }
   b, err = ioutil.ReadAll(resp.Body)
   resp.Body.Close()
   if err != nil {
       log.Fatal(err)
   }
   fmt.Println(string(b))

}</lang>

Kotlin

<lang scala>// version 1.2.0

import java.net.Authenticator import java.net.PasswordAuthentication import javax.net.ssl.HttpsURLConnection import java.net.URL import java.io.InputStreamReader import java.io.BufferedReader

object PasswordAuthenticator : Authenticator() {

   override fun getPasswordAuthentication() =
       PasswordAuthentication ("username", "password".toCharArray())

}

fun main(args: Array<String>) {

   val url = URL("https://somehost.com")
   val con = url.openConnection() as HttpsURLConnection
   Authenticator.setDefault(PasswordAuthenticator)
   con.allowUserInteraction = true
   con.connect()
   val isr = InputStreamReader(con.inputStream)
   val br = BufferedReader(isr)
   while (true) {
       val line = br.readLine()
       if (line == null) break
       println(line)
   }

}</lang>

Lasso

<lang Lasso>local(username = 'hello',password = 'world') local(x = curl('https://sourceforge.net'))

  1. x->set(CURLOPT_USERPWD, #username + ':' + #password)

local(y = #x->result)

  1. y->asString</lang>

LiveCode

HTTP Basic Auth as part of url <lang LiveCode>command getAuthWebResource

   libURLFollowHttpRedirects true
   libURLSetSSLVerification true
   put URL "https://user:passwd@example.basicauth.com/" into response
   put response

end getAuthWebResource</lang>

You can also set the headers for the basic auth requests <lang LiveCode>command getAuthWebResource

   libURLFollowHttpRedirects true
   libURLSetSSLVerification true
   set the httpHeaders to "Authorization: Basic " && base64Encode("user:passwd")
   put URL "https://example.basicauth.com" into response
   put response

end getAuthWebResource</lang>

Mathematica / Wolfram Language

<lang Mathematica>a = RunThrough["curl -u JohnDoe:Password https://www.example.com", 1] For[ i=0, i < Length[a] , i++, SomeFunction[a]]</lang>

Perl

Library: LWP

<lang perl>use LWP::UserAgent qw(); my $ua = LWP::UserAgent->new; my $netloc = 'http://www.buddhism-dict.net/cgi-bin/xpr-dealt.pl:80'; $ua->credentials(

  $netloc,
  'CJK-E and Buddhist Dictionaries', # basic realm
  'guest',  # user
  ,       # empty pw

); my $response = $ua->get($netloc);

use WWW::Mechanize qw(); my $mech = WWW::Mechanize->new; $mech->get('https://login.yahoo.com/'); $mech->submit_form(with_fields => {

   login         => 'XXXXXX',
   passwd        => 'YYYYYY',
   '.persistent' => 'y',  # tick checkbox

});</lang>

Perl 6

Works with: Rakudo version 2017.09

Used here to connect to my local wireless router to a page that is password protected. Obviously not going to be generally publicly accessible but should be easily adaptable to other sites / devices.

<lang perl6>use HTTP::UserAgent;

my $username = 'username'; # my username my $password = 'password'; # my password my $address = 'http://192.168.1.1/Status_Router.asp'; # my local wireless router

my $ua = HTTP::UserAgent.new; $ua.auth( $username, $password ); my $response = $ua.get: $address; say $response.is-success ?? $response.content !! $response.status-line;</lang>

PicoLisp

<lang PicoLisp>(let (User "Bill" Pass "T0p5ecRet" Url "https://www.example.com")

  (in (list 'curl "-u" (pack User ': Pass) Url)
     (while (line)
        (doSomeProcessingWithLine @) ) ) )</lang>

Python

Works with: Python version 2.4 and 2.6

Note: You should install mechanize to run code below. Visit: http://wwwsearch.sourceforge.net/mechanize/

<lang python>#!/usr/bin/python

  1. -*- coding: utf-8 -*-

from mechanize import Browser

USER_AGENT = "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.8.1.9) Gecko/20071102 Pardus/2007 Firefox/2.0.0.9"

br = Browser() br.addheaders = [("User-agent", USER_AGENT)]

  1. remove comment if you get debug output
  2. br.set_debug_redirects(True)
  3. br.set_debug_responses(True)
  4. br.set_debug_http(True)

br.open("https://www.facebook.com")

br.select_form("loginform") br['email'] = "xxxxxxx@xxxxx.com" br['pass'] = "xxxxxxxxx" br['persistent'] = ["1"]

response = br.submit() print response.read()</lang>

Racket

<lang racket>

  1. lang racket

(require net/url net/url-connect openssl)

(module+ main

 (parameterize ([current-https-protocol (ssl-make-client-context)])
   (ssl-set-verify! (current-https-protocol) #t)
   ;; When this is #f, we correctly get an exception:
   ;; error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
   (when #t
     (ssl-load-verify-source! (current-https-protocol)
                              '(directory
                                ;; This location works on Debian 6;
                                ;; adjust as needed for your platform.
                                "/etc/ssl/certs"
                                )))
   (for ([l (in-port read-line (get-pure-port (string->url "https://www.google.com/")))])
     (displayln  l))))

</lang>

Run BASIC

<lang runbasic>html "

LOGIN
UserName"
TEXTBOX #userName, "" 
html "
Password:"

PasswordBox #passWord, ""

html "
"

button #si, "Signin", [doSignin] html " " button #ex, "Exit", [exit]

html "
"

WAIT

[doSignin] loginUserName$ = trim$(#userName contents$()) loginPassWord$ = trim$(#passWord contents$()) if (loginUserName$ = "admin" and loginPassWord$ = "admin" then

  print "Login ok"
 else
  print "invalid User or Pass"
  cls
  goto [loop]

end if

print Platform$ ' OS where Run BASIC is being hosted print UserInfo$ ' Information about the user's web browser print UserAddress$ ' IP address of the user

[exit] end</lang>  

Sidef

<lang ruby>require('WWW::Mechanize')

var mech = %s'WWW::Mechanize'.new(

   cookie_jar => Hash.new,
   agent => 'Mozilla/5.0',

)

mech.get('https://login.yahoo.com/') mech.submit_form(

   form_id => 'mbr-login-form',   # form id
   fields => Hash.new(
       'login'  => 'XXXXXX',
       'passwd' => 'YYYYYY',

))</lang>

Tcl

Works with: Tcl version 8.6
for the binary encode subcommand, otherwise uses
Library: Tcllib (Package: base64)

Uses the Tls package. <lang Tcl>package require http package require tls http::register https 443 ::tls::socket

  1. Generate the authentication

set user theUser set pass thePassword dict set auth Authenticate "Basic [binary encode base64 ${user}:${pass}]"

  1. Make a secure authenticated connection

set token [http::geturl https://secure.example.com/ -headers $auth]

  1. Now as for conventional use of the “http” package

set data [http::data $token] http::cleanup $token</lang>

zkl

Using cURL to do the heavy lifting, get a XML list of computers connected to my router. <lang zkl>zkl: var ZC=Import("zklCurl") zkl: var data=ZC().get("http://usr:pw@192.168.1.1/computer_list.xml") L(Data(1,049),121,0) zkl: data[0][121,*].text</lang>

Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<computers>
<ip_address0>192.168.1.100</ip_address0><host_name0>core-shot
...