From b1ccc69155c659c22f540cd96204e92981c0e6ea Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Thu, 11 Aug 2016 15:42:04 -0400 Subject: [PATCH] contrib: add shibuqam to extract information from a shibboleth authentication Signed-off-by: Jean Privat --- contrib/shibuqam/examples/reloadgame.nit | 115 ++++++++++++++++++++++++++++++ contrib/shibuqam/package.ini | 11 +++ contrib/shibuqam/shibuqam.nit | 69 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 contrib/shibuqam/examples/reloadgame.nit create mode 100644 contrib/shibuqam/package.ini create mode 100644 contrib/shibuqam/shibuqam.nit diff --git a/contrib/shibuqam/examples/reloadgame.nit b/contrib/shibuqam/examples/reloadgame.nit new file mode 100644 index 0000000..24eecf5 --- /dev/null +++ b/contrib/shibuqam/examples/reloadgame.nit @@ -0,0 +1,115 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Example that uses `shibuqam` to authenticate users and count the number of time they reload. +module reloadgame + +import popcorn +import counter +import shibuqam + +redef class User + # How many reload? + var seen = 0 +end + +# Ugly global class to track the knowledge. +class DB + # All known users + var users = new HashMap[String, User] +end +# Ugly global instance to track the knowledge. +fun db: DB do return once new DB + +redef class HttpRequest + # Like `user` but reuse an user if already seen + var reuser: nullable User is lazy do + var user = self.user + if user == null then return null + + var saved = db.users.get_or_null(user.id) + if saved != null then return saved + + db.users[user.id] = user + return user + end +end + +# The only handler of the example. +class ReloadGame + super Handler + + redef fun get(http_request, response) + do + var body = """ + + + + + Nitcorn on Shibboleth/UQAM + + +
+

Nitcorn on Shibboleth/UQAM

+ """ + + var user = http_request.user + + if user != null then + user.seen += 1 + + body += """ +

Welcome {{{user.given_name}}}

+
    +
  • Full Name: {{{user.display_name}}}
  • +
  • E-Mail: {{{user.email}}}
  • +
  • Id: {{{user.id}}}
  • +
  • Score: {{{user.seen}}}
  • +
+ """ + + #for k, v in http_request.header do body += "
  • {k}: {v}
  • " + else + # The login page, at the location the reverse proxy is expected to be configured + # to force an authentication. + var login = "/securep/login" + body += """ +

    Welcome annonymous, please log in.

    + """ + end + + var score = new Counter[User] + for u in db.users.values do + score[u] = u.seen + end + + body += "

    Scoreboard

      " + for u in score.sort.reversed do + body += "
    • {u.display_name}: {u.seen}
    • " + end + + + body += """
    +
    + + + """ + + response.html body + end +end + +var app = new App +app.use("/*", new ReloadGame) +app.listen("localhost", 3000) diff --git a/contrib/shibuqam/package.ini b/contrib/shibuqam/package.ini new file mode 100644 index 0000000..8c619ad --- /dev/null +++ b/contrib/shibuqam/package.ini @@ -0,0 +1,11 @@ +[package] +name=shibuqam +tags=web +maintainer=Jean Privat +license=Apache-2.0 +[upstream] +browse=https://github.com/nitlang/nit/tree/master/contrib/shibuqam/ +git=https://github.com/nitlang/nit.git +git.directory=contrib/shibuqam/ +homepage=http://nitlanguage.org +issues=https://github.com/nitlang/nit/issues diff --git a/contrib/shibuqam/shibuqam.nit b/contrib/shibuqam/shibuqam.nit new file mode 100644 index 0000000..e8da9a5 --- /dev/null +++ b/contrib/shibuqam/shibuqam.nit @@ -0,0 +1,69 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Gather the authenticated users on UQAM websites. +# +# The main method to use is `HttpRequest::user` and it extracts the information +# of the authenticated user from the request header. +# The real authentication must be done by a mandatory reverse proxy server. +module shibuqam + +import nitcorn +private import md5 + +# Information on a user from Shibboleth/UQAM +class User + # The *code permanent* (or the uid for non student) + var id: String + + # Usually the first name + var given_name: String + + # Usually "FamilyName, FirstName" + var display_name: String + + # The email @courrier.uqam.ca (or @uqam.ca for non student) + var email: String + + # The Gravatar URL (based on `email`) + var avatar: String is lazy do + var md5 = email.md5 + return "https://www.gravatar.com/avatar/{md5}?d=retro" + end +end + +redef class HttpRequest + # Extract the Shibboleth/UQAM information from the header, if any. + # + # We assume that a reverse proxy does the authentication and fill the request header. + # If the server is accessible directly, these headers can be easily forged. + # Thus, we assume that the reverse proxy is not by-passable. + # + # The reverse proxy might choose to force an authentication or not. + # If there is no authentication, there is no information in the request header (or with the `(null)` value). + # In this case, `null` is returned by this function. + fun user: nullable User do + var user = header.get_or_null("Remote-User") + if user == null or user == "(null)" then return null + + var display_name = header.get_or_null("User-Display-Name") + var given_name = header.get_or_null("User-Given-Name") + var email = header.get_or_null("User-Mail") + + if display_name == null or given_name == null or email == null then return null + + var res = new User(user, given_name, display_name, email) + return res + end +end -- 1.7.9.5