8

My company uses an LDAP server for authentication against an Active Directory. I need to authenticate users of a remotely hosted Shiny app using this. I managed to authenticate in Python, but need to port this to R:

import ldap
from getpass import getpass
username = "user_name"
password = getpass(prompt='Password: ', stream=None)
ldap_server = "ldap://company-ldap-server:636"

try:
    # Create connection with LDAP server and set options
    conn = ldap.initialize(ldap_server)
    conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
    conn.set_option(ldap.OPT_X_TLS_NEWCTX, 0)

    # Authenticate by trying to connect
    conn.simple_bind_s(username, password)

    # Retrieve this user's name and email (for authorization)
    info = conn.search_s("DC=ad,DC=company,DC=com", ldap.SCOPE_SUBTREE, f"cn={username}*")
    conn.unbind_s()

except Exception:
    print("ERROR: Could not connect")

Here's what I've tried in R:

library(RCurl)

ldap_server <- "ldap://company-ldap-server:636"
user <- "user_name"
RCurl::getURL(ldap_server, .opts=list(userpwd = paste0(user, "@ad.company.com:", 
                                                       .rs.askForPassword("Password: "))
                                      )
)

All I get is:

Error in function (type, msg, asError = TRUE) : LDAP local: bind ldap_result Can't contact LDAP server

In curlOptions() there are some items similar to OPT_X_TLS_REQUIRE_CERT and OPT_X_TLS_NEWCTX, but curlSetOpts with any of those names don't seem to work.

This question and answer comes close, but I want to authenticate a user by securely passing their username and password.

In this answer, they're trying to convert Shiny LDAP to flask (basically the opposite of mine). But I'm not sure where/how they specify that auth_active_dir configuration...perhaps R Studio Connect or Shiny Open Server Pro. Neither of which are options for me.

It could be that the server is down at the moment. In the meantime, are these equivalent or is there something I'm missing in the R code?

# Python
conn = ldap.initialize(ldap_server)
conn.simple_bind_s(username, password)

# R
getURL(ldap_server, .opts=list(userpwd = "...."))
Wassadamo
  • 1,176
  • 12
  • 32
  • 1
    Not sure how you are deploying your app but just FYI: The commercial versions of Shiny Server supports LDAP authentication, see [this](https://support.rstudio.com/hc/en-us/articles/214577747-Configuring-Shiny-Server-Pro-with-LDAP-or-Active-Directory). Furthermore the open source solution [shinyproxy](https://www.shinyproxy.io/configuration/#authentication) provides LDAP support. – ismirsehregal Oct 09 '19 at 12:46
  • The paid version of Shiny Server is less than ideal, although I might go there if no other options work. Shinyproxy requires docker which has been a monumental pain before. Perhaps time to give it another try – Wassadamo Oct 09 '19 at 16:42
  • 2
    There are example containers available for shinyproxy. It took me only a few hours to deploy/configure my first app (also using LDAP) this way. – ismirsehregal Oct 09 '19 at 19:16
  • As intriguing as shinyproxy is, I've confirmed docker is not an option either. – Wassadamo Oct 09 '19 at 22:06
  • Did you ever figure this out? – Frank Apr 28 '20 at 18:47
  • 2
    Nope. I've been handling it just by calling a Python script which does the LDAP auth with a system call. Might be a slightly more elegant method using reticulate. But it's all awkward imo. – Wassadamo Apr 28 '20 at 20:22
  • have a look at [this blogpost](https://www.statworx.com/de/blog/how-to-dockerize-shinyapps/) for how to dockerize shiny apps – mnist Nov 23 '21 at 22:52
  • Maybe, you could try my rlang lib - https://github.com/dmslabsbr/ShinyLdap It is still a beta version, but I´m using in some projects. – Daniel Nov 23 '21 at 21:35

1 Answers1

0

The format of your url (ldap_server) is not enough. How about you try: Following the post here: How do I run a ldap query using R?

ldap_server <- "ldap://company-ldap-server:636/OU=[value],dc=ad,dc=company,dc=com?cn,mail?sub?filter"
  • Replace the [value] by removing bracket with your OU.
  • sub is scope (base/one/sub) as values
  • Replace "cn, mail" with whatever attributes you want to query
  • filter is search filter making subset of the query: eg(sn=LastName).

Check out https://docs.oracle.com/cd/E19396-01/817-7616/ldurl.html for curl url.