Module: Authenticator

Extended by:
Authenticator
Included in:
Authenticator
Defined in:
lib/magister/authenticator.rb

Overview

A module used to authenticate a user with the magister api.

Instance Method Summary collapse

Instance Method Details

#login(username, password, school) ⇒ Object

Log in with username and password

Parameters:

  • username (String)

    The username, usually in the form of a “leerlingnummer”

  • password (String)

    The users password

  • school (String)

    The school the user attends

Since:

  • 1.1.0



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/magister/authenticator.rb', line 22

def (username, password, school)
    # uri = URI("https://#{school}.magister.net/oidc_config.js")
    # http = Net::HTTP.new(uri.host, uri.port)
    # http.use_ssl = true
    # request = Net::HTTP::Get.new(uri.request_uri)
    # response = http.request(request)
    # oidc_conf = (response.body.split("config =").last.split("};").first.gsub("window.location.hostname", "'" + uri.hostname + "'") + "}").gsub(': ', '":').gsub(/,(\s*)/, ',"').gsub(/{(\s*)/, '{"').gsub("'", '"').gsub('" + "', "")

    # oidc_conf = JSON.parse(oidc_conf)
    if $magister_useCache && File.exist?($magister_cachingDirectory + "/auth.json")
        f = File.open($magister_cachingDirectory + "/auth.json")
        cached_data = f.read
        cached_data = JSON.parse(cached_data)
        expires = Time.at(cached_data["expires"].to_i)
        puts "attempting to use cached token..."
        if expires.to_i > Time.now.to_i
          puts "using cached token."
          return Profile.new(cached_data["token"], school)
        else
          puts "cached token expired."
        end
    end

    codeVerifier  = SecureRandom.alphanumeric(128)
    verifier      = Base64.urlsafe_encode64(codeVerifier)

    rawChallenge = Digest::SHA256.hexdigest verifier
    challenge = Base64.urlsafe_encode64(rawChallenge)

    @@state = SecureRandom.hex(16)
    @@nonce = SecureRandom.hex(16)

    auth_uri = "https://#{school}.magister.net/connect/authorize?client_id=M6LOAPP&redirect_uri=m6loapp%3A%2F%2Foauth2redirect%2F&scope=openid%20profile%20opp.read%20opp.manage%20attendance.overview%20attendance.administration%20calendar.ical.user%20calendar.to-do.user%20grades.read%20grades.manage&state=#{@@state}&nonce=#{@@nonce}&code_challenge=#{challenge}&code_challenge_method=S256&prompt=select_account"
    # puts "using authentication url #{auth_uri}"

    token = ""
    if $authMode == "local"
        raise NotImplementedError.new("\n\nLocal authentication mode has not been implemented yet, \nCheck our github for any updates, or if you want to help implementing it!\n")
    else
        puts "Using Selenium with Chrome for authentication."
        options = Selenium::WebDriver::Options.chrome(args: ['--headless=new'])
        driver = Selenium::WebDriver.for :chrome, options: options

        driver.get auth_uri
        while !driver.current_url.start_with? "https://accounts.magister.net/account/login"
            sleep(0.5)
            # puts "waiting for load..."
        end
        sleep(3)

        username_field = driver.find_element(id: 'username')
        username_field.send_keys(username)
        go_to_password_button = driver.find_element(id: 'username_submit')
        go_to_password_button.click

        sleep(1)

        password_field = driver.find_element(id: 'password')
        password_field.send_keys(password)
         = driver.find_element(id: 'password_submit')
        .click

        wait = Selenium::WebDriver::Wait.new(timeout: 30)
        wait.until { driver.current_url.start_with? "https://#{school}.magister.net/oidc/redirect_callback.html" }

        expires_in = driver.current_url.split("expires_in=").last.split("&").first.to_i
        expires = Time.now + expires_in
        token = driver.current_url.split("access_token=").last.split("&").first

        driver.quit
    end

    if $magister_useCache
        if $magister_cacheType == "json"
          File.write($magister_cachingDirectory + "/auth.json", "{\"token\": \"#{token}\", \"expires\": \"#{expires.to_i}\"}")
        end
    end

    return Profile.new(token, school)
end