Upgrade to Pro — share decks privately, control downloads, hide ads and more …

When Cro is not a Web Framework: Implementing LDAP for Perl 6

When Cro is not a Web Framework: Implementing LDAP for Perl 6

Overview of Cro::LDAP Perl 6 module which includes general means behind Cro::Core module, overview of Cro::LDAP internals and its API.

Altai-man

August 08, 2019
Tweet

More Decks by Altai-man

Other Decks in Programming

Transcript

  1. When Cro is not a Web Framework: Implementing LDAP for

    Perl 6 or “ My Cro stands for「Mi-cro」”
  2. Plan • Cro::Core • LDAP protocol • Cro::LDAP::Types • Cro::LDAP

    Internals • Cro::LDAP::Client API • Conclusions
  3. Cro::Core A library for building distributed, reactive systems that uses

    Perl 6 concurrency primitives to express data flow in a natural way (and just a tiny bit more)
  4. Events The real world happens in real time It supplies

    us with events: network packets file changes, logs
  5. Events The real world happens in real time It supplies

    us with events: network packets file changes, logs user input
  6. Events The real world happens in real time It supplies

    us with events: network packets file changes, logs user input device events etc etc
  7. Processing • Take logs and filter them • Take filtered

    logs and mark some of them • Take marked, filtered logs and compress them • Take compressed files and send them to a backup server …Take Filter! Mark! Compress! Send…
  8. Cro::Core • Cro::Core is a library to build (micro)services that

    can communicate with each other using different means.
  9. Cro::Core • Cro::Core is a library to build (micro)services that

    can communicate with each other using different means. • It is packed with simple and smart primitives for inputs, transformers, outputs.
  10. Cro::Core • Cro::Core is a library to build (micro)services that

    can communicate with each other using different means. • It is packed with simple and smart primitives for inputs, transformers, outputs. • Cro as a project is a set of libraries built upon this idea.
  11. Cro::Core • Cro::Core is a library to build (micro)services that

    can communicate with each other using different means. • It is packed with simple and smart primitives for inputs, transformers, outputs. • Cro as a project is a set of libraries built upon this idea. • It allows the user to think about logic – and handles delivery.
  12. LDAP • A binary, client-server network protocol to work with

    Directory Service Providers. • The server managing the Directory keeps your data in a hierarchical database.
  13. LDAP • A binary, client-server network protocol to work with

    Directory Service Providers. • The server managing the Directory keeps your data in a hierarchical database. • You can add, modify, remove, query etc data using an LDAP client.
  14. LDAP Client and server communicate by sending LDAP messages to

    each other LDAP Message • ID 1 • Request • Controls LDAP Message • ID 2 • Request • Controls LDAP Message • ID 3 • Request • Controls … LDAP Message • ID 1 • Response • Controls LDAP Message • ID 2 • Response • Controls LDAP Message • ID 3 • Response • Controls …
  15. LDAP • All messages have common pieces (id, controls). •

    Every message carries either a request or a response. • Particular request/response types represent LDAP operations (bind, add, modify, search etc). • All data types used in LDAP are described using the ASN.1 specification language and the Basic Encoding Rules of ASN.1.
  16. Cro::LDAP::Types • There are a lot of types there, and

    we also need to encode and decode them into bytes to send over sockets. • How Perl 6 handles it…
  17. Cro::LDAP::Types use Cro; use ASN::Types; use ASN::META <file docs/ldap.asn>; class

    Cro::LDAP::Message is LDAPMessage does Cro::Message { method trace-output(--> Str) { "LDAP MSG [{self.message-id}] {self.protocol-op.choice-value.key.tc}" } } my $map := MY::.pairs .grep({ .key ~~ /^ <[a..zA..Z]>/ && .key ne <EXPORT GLOBALish>.any}) .Map; sub EXPORT() { $map; }
  18. Cro::LDAP::Client Take user input (API) Create a message (source) Encode

    the message (transform) Send… (sink) (maybe do a lot of other things)
  19. Cro::LDAP::Client Take user input (API) Create a message (source) Encode

    the message (transform) Send… (sink) (maybe do a lot of other things) Get bytes (source)
  20. Cro::LDAP::Client Take user input (API) Create a message (source) Encode

    the message (transform) Send… (sink) (maybe do a lot of other things) Get bytes (source) Parse (transform)
  21. Cro::LDAP::Client Take user input (API) Create a message (source) Encode

    the message (transform) Send… (sink) (maybe do a lot of other things) Get bytes (source) Parse (transform) Return to the user (sink)
  22. Cro::LDAP::Client Take user input (API) Create a message (source) Encode

    the message (transform) Send… (sink) (maybe do a lot of other things) Get bytes (source) Parse (transform) Return to the user (sink) Save the World
  23. Cro::LDAP::Server (in progress) Take bytes (source) Parse (transform) Pass to

    a real Directory Provider (sink) Having a response, emit it (source) Send bytes back (sink) Serialize (transform)
  24. Cro::LDAP::Client API (1/3) my Cro::LDAP::Client $ldap = await Cro::LDAP::Client.connect("ldap://test"); given

    $ldap.bind(name => “foo=bar", password => “horse") -> $bind { process-error($bind) unless $bind.result-code ~~ success; }
  25. Cro::LDAP::Client API (1/3) my Cro::LDAP::Client $ldap = await Cro::LDAP::Client.connect("ldap://test"); given

    $ldap.bind(name => “foo=bar", password => “horse") -> $bind { process-error($bind) unless $bind.result-code ~~ success; } my $search = $ldap.search(:dn<dn=cool>, :filter(‘lang=Perl 6’));
  26. Cro::LDAP::Client API (1/3) my Cro::LDAP::Client $ldap = await Cro::LDAP::Client.connect("ldap://test"); given

    $ldap.bind(name => “foo=bar", password => “horse") -> $bind { process-error($bind) unless $bind.result-code ~~ success; } my $search = $ldap.search(:dn<dn=cool>, :filter(‘lang=Perl 6’)); react whenever $search { when Cro::LDAP::Entry { say $_.dn; for $_.attributes.kv -> $attr, $value { #`[ process values… ] } } when Cro::LDAP::Reference { #`[ process reference ] } }
  27. Cro::LDAP::Client API (2/3) given await $ldap.add(“dn=new", attrs => [givenName =>

    ‘Tester’]]) -> $add { # process error here } given await $ldap.modifyDN(:dn<dn=new>, new-dn => “dn=newer") -> $moddn { # process error here }
  28. Cro::LDAP::Client API (2/3) given await $ldap.add(“dn=new", attrs => [givenName =>

    ‘Tester’]]) -> $add { # process error here } given await $ldap.modifyDN(:dn<dn=new>, new-dn => “dn=newer") -> $moddn { # process error here } my @changes = replace => [:givenName['Robot']]; given await $ldap.modify(“dn=newer", @changes) -> $modify { # always check your responses }
  29. Cro::LDAP::Client API (2/3) given await $ldap.add(“dn=new", attrs => [givenName =>

    ‘Tester’]]) -> $add { # process error here } given await $ldap.modifyDN(:dn<dn=new>, new-dn => “dn=newer") -> $moddn { # process error here } my @changes = replace => [:givenName['Robot']]; given await $ldap.modify(“dn=newer", @changes) -> $modify { # always check your responses } given await $ldap.compare(“dn=newer", “givenName", 'Tester') -> $compare { say $compare.result-code; # compareFalse… }
  30. Cro::LDAP::Client API (2/3) given await $ldap.add(“dn=new", attrs => [givenName =>

    ‘Tester’]]) -> $add { # process error here } given await $ldap.modifyDN(:dn<dn=new>, new-dn => “dn=newer") -> $moddn { # process error here } my @changes = replace => [:givenName['Robot']]; given await $ldap.modify(“dn=newer", @changes) -> $modify { # always check your responses } given await $ldap.compare(“dn=newer", “givenName", 'Tester') -> $compare { say $compare.result-code; # compareFalse… } given await $ldap.delete(“dn=newest”) -> $delete { say $delete.result-code; # hopefully, success say $delete.error-message; # hopefully, none, but always check your responses }
  31. Cro::LDAP::Client API (3/3) # LDIF file sample version: 1 dn:

    uid=test,ou=people,dc=test,dc=local objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: test cn: test givenName: Test # base64 decoded value givenName;lang-ja:: 44OG44K544OI sn: Tester
  32. Cro::LDAP::Client API (3/3) # LDIF changes file sample version: 1

    # Add a new entry dn: dc=test changetype: add objectclass: top telephonenumber: +1 408 555 1212 jpegphoto:< file://t/testdata/test.jpg # Delete an existing entry dn: dc=test1 changetype: delete # Modify an entry’s relative distinguished name dn: dc=test3 changetype: modrdn newrdn: dc=test3backup deleteoldrdn: 1
  33. Sync your stuff Want to add some entries to your

    Directory? Maybe even modify some entries today?
  34. Sync your stuff Want to add some entries to your

    Directory? Maybe even modify some entries today? Fear no more, just sync your data!
  35. Sync your stuff my @entries = Cro::LDAP::Entry.parse($ldif-text); my @resps =

    await $client.sync(@entries); for @resps -> $response { # hereby I vow to always check my responses, # if they were successful or not, # and react upon this now and forever! }
  36. TODO • LDAPS is done, StartTLS is a Work in

    Progress • Complete the server middleware • Make Cro::LDAP::Client smarter • More proper error handling • Squash some bugs
  37. TODO • LDAPS is done, StartTLS is a Work in

    Progress • Complete the server middleware • Make Cro::LDAP::Client smarter • More proper error handling • Squash some bugs • Be helpful for Perl 6 coders! VERY IMPORTANT!
  38. Conclusions • A lot of common things just work •

    Some not so common things are a work in progress
  39. Conclusions • A lot of common things just work •

    Some not so common things are a work in progress • Cro::LDAP welcomes any bug reports, suggestions, ideas
  40. Conclusions • A lot of common things just work •

    Some not so common things are a work in progress • Cro::LDAP welcomes any bug reports, suggestions, ideas • Perl 6 delivers!