class: center, middle, inverse, title-slide # Authentication and authorization in plumber with the sealr package ### Frie Preu
(
@ameisen_strasse
)
### codecentric AG --- class: center, middle ## sealr co-author: Jan Dix  <br>
[toll_patsch](https://twitter.com/toll_patsch) --- class: center, middle # The why -- # Security ~~should~~ must be easy ??? not should but must. in my experience security measures are not adopted even IF easy. --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## Examples -- + password security -- + 2FA authentication -- + PGP encryption + disk encryption + ... -- --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## Securing plumber APIs? + many dimensions<sup>1</sup>, here: focus on Authorization and Authentication .footnote[<sup>1</sup>[https://www.rplumber.io/docs/security.html](https://www.rplumber.io/docs/security.html)] --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> .pull-left[ ### Authentication verifying an identity  Image by <a href="https://pixabay.com/users/webandi-1460261/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1051697">Andreas Lischka</a> from <a href="https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1051697">Pixabay</a> --> plumber API: check credentials (e.g. login) ] -- .pull-right[ ### Authorization verifying access rights / permissions to do something  Image by <a href="https://pixabay.com/users/BilliTheCat-7996303/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=3312365">Nina Garman</a> from <a href="https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=3312365">Pixabay</a> --> plumber API: checking permissions to access endpoint(s) xyz ] --- class: middle, center ## sealr mission > The goal of sealr is to provide multiple authentication and authorization strategies for plumber by using filters. In doing so, we hope to make best practices in authentication easy to implement for the R community.<sup>1</sup> .footnote[<sup>1</sup>https://github.com/jandix/sealr/README.md ] --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## Disclaimer  .footnote[https://github.com/jandix/sealr/README.md ] --- class: center, middle # How? -- # sealr features and implementation --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## passport.js <img src="img/passport_strategies.png" width="70%" height="70%" /> --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## passport.js ### Consistent interface -- 1. specify and configure strategy Object, e.g. `FacebookStrategy` - optionally: write custom code for checking authentication -- 2. use `passport.authenticate()`, e.g. `passport.authenticate('facebook')` to authenticate calls to endpoints --- class: center, middle # Example --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## R Memes for Statistical Fiends .pull-left[  .footnote[Source: [https://pbs.twimg.com/profile_images/932954186278428672/67uSz6gN_400x400.jpg](https://pbs.twimg.com/profile_images/932954186278428672/67uSz6gN_400x400.jpg)] ] -- .pull-right[ -
[R Memes for Statistical Fiends](https://www.facebook.com/Rmemes0/) -
[rstatsmemes](https://twitter.com/rstatsmemes) -
[r/rstatsmemes](https://www.reddit.com/r/rstatsmemes/) -
[favstats/rstatsmemes](https://github.com/favstats/rstatsmemes) > Ever wanted to have R Memes at the ready whenever you want? Of course not. But here is a package that does exactly that. ] --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## [frie.codes/rstatsmemes](frie.codes/rstatsmemes) <video controls="controls" width="800" height="500" name="Video Name" src="img/demo.mov"></video> --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## [frie.codes/rstatsmemes](frie.codes/rstatsmemes)  --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## [frie.codes/rstatsmemes](frie.codes/rstatsmemes)  ---  --  --  --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## Strategy configuration - not implemented in sealr because unique to use case - custom code needed - but examples in /examples folder & in docs! --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## rstatsmemes: strategy configuration ```r pr$handle("POST", "/authentication", function (req, res, user = NULL, password = NULL) { # check if user provided credentials if (is.null(user) || is.null(password)) { res$status <- 404 return(sealr::is_authed_return_list(FALSE, "Failed.", 404, "User or password wrong.")) } # find user in database index <- match(user, users$user) # check if user exist if (is.na(index)) { res$status <- 401 return(sealr::is_authed_return_list(FALSE, "Failed.", 401, "User or password wrong.")) } # check if password is correct if (!bcrypt::checkpw(password, users$password[index])){ res$status <- 401 return(sealr::is_authed_return_list(FALSE, "Failed.", 401, "User or password wrong.")) } ``` --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ```r # define jwt payload # information about the additional fields can be found at # https://tools.ietf.org/html/rfc7519#section-4.1 payload <- jose::jwt_claim(userID = users$id[index]) # convert secret to bytes secret_raw <- charToRaw(secret) # encode token using the secret jwt <- jose::jwt_encode_hmac(payload, secret = secret_raw) # return jwt as response return(jwt = jwt) *}, preempt = c("auth")) ``` --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## rstatsmemes: sealr authenticate - goal: protect `/meme/<no>/stats`, leave `/meme` unprotected -- - filter(s): "[...] “pipeline” for handling incoming requests."<sup>1</sup> -- ```r pr$filter("auth", function (req, res) { sealr::authenticate(req = req, # plumber object: the request from the user res = res, # plumber object: the response list * is_authed_fun = sealr::is_authed_jwt, # checker fun token_location = "header", secret = secret) # arguments passed to the checker function }) ``` -- - authenticate: small wrapper function. -- - is_authed_fun (**checker function**): check whether authed - is_authed_jwt: can the JWT be decrypted, ...? - (is_authed_oidc_google: is this JWT a valid Google JWT, ...?) .footnote[<sup>1</sup>https://www.rplumber.io/docs/routing-and-input.html#filters] --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## rstatsmemes: Protect endpoints ```r pr$handle("GET", "/meme/<no>/stats", function(req, res, no){ no <- as.integer(no) stats <- memes %>% dplyr::filter(meme_number == no) %>% dplyr::slice(1) %>% # make sure only one is returend dplyr::select(meme_number, shares_count, likes_count, comments_count) return(as.list(stats)) }, serializer = plumber::serializer_unboxed_json()) ``` -- ```r pr$handle("GET", "/meme", function(req, res){ # get a random meme random_meme <- memes %>% dplyr::sample_n(1) %>% dplyr::select(meme_number, message, full_picture) return(as.list(random_meme)) }, serializer = plumber::serializer_unboxed_json(), * preempt = c("auth") ) ``` --- class: center, middle # Outlook -- # Plans for sealr --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## Plans for sealr ### short-term - finish / polish docs - extend / another "real world" implementation -- ### mid- / long-term - develop more strategies - provide more examples for strategy configuration (/authentication) - provide tooling (docker image...) --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> # How you can help ### **Talk to us!** 💬 - use cases + real world set-ups -- ### **Try sealr!** - keep in mind the disclaimer! - file issues / feature requests on GitHub -- ### **Write/review code** - review code / docs - write code / docs - provide examples --- <div> <div class="col2"></div> <div id="ribbon-content"> <img src="img/cc_ribbon_bw.png" class="ribbon"/> </div> </div> ## All you need to know! - .yellow[Slides: [https://frie.codes/user2019_slides](https://frie.codes/user2019_slides)] - .yellow[Demo: [frie.codes/rstatsmemes/](frie.codes/rstatsmemes/)] - plumber website: [rplumber.io](https://rplumber.io) - sealr GitHub Repo: [https://github.com/jandix/sealr](https://github.com/jandix/sealr) - Bookdown Docs (WIP): [https://jandix.github.io/sealr](https://jandix.github.io/sealr) - Talk (code + slides): [https://github.com/friep/sealr_useR2019](https://github.com/friep/sealr_useR2019) .pull-left[ ### Frie Preu +
data scientist / IT consultant @ [codecentric AG](https://www.codecentric.de) +
[friep](https://github.com/friep) +
[ameisen_strasse](https://twitter.com/ameisen_strasse) ] .pull-right[ ### Jan Dix +
data scientist, frontend developer +
[jandix](https://github.com/jandix) +
[toll_patsch](https://twitter.com/toll_patsch) ]