Fork me on GitHub
#beginners
<
2019-08-16
>
Jamie Rumbelow14:08:43

Today is the first day that I write Clojure professionally; for real money 😍

parrot 32
🎉 40
aw_yeah 24
🙌 16
metal 8
📈 4
Ashley Smith15:08:10

Hey, so it is now time for me to learn about security - I know this is an absolutely HUGE topic for the scope of this slack, but I wanted to know if anyone here had used buddy for creating sign in tokens? My goal is to have the user submit their username and password once and only once, receive a token that is valid for a certain amount of time, and use that for all further communication. However, having never touched security before, I'm trying to find my entry point. Is buddy-sign a good package for this? Tough position to be in

Ashley Smith15:08:24

im probably going to follow this, just intimidated https://rundis.github.io/blog/2015/buddy_auth_part1.html

lispyclouds15:08:59

The Signed JWT Auth Example is probably what you'd want?

Ashley Smith15:08:03

It sounds like it but im not quite sure how it truly works

Alex Miller (Clojure team)15:08:06

@ashley this is not an answer to your question, but I think it's a great high-level talk about key topics in web security for Clojure apps per OWASP https://www.youtube.com/watch?v=lRHPZXKQVLk

Ashley Smith15:08:23

I'll give it a watch as that sounds like something I need to see

Alex Miller (Clojure team)15:08:47

it will give you a map for thinking about it at least

Ashley Smith15:08:59

I'm not sure about the 'self contained' part of the JWT auth example, if the client doesn't accept the token, how does the server distinguish between clients?

ghadi15:08:52

what do you mean by "if the client doesn't accept the token"?

Ashley Smith15:08:54

This type of token mechanism enables a complete stateless authentication because the server does not need to store the token and related information, the token will contain all the needed information for authentication.
So, I don't understand this because it refers to this needed information, but I don't know what exactly this is

lispyclouds15:08:25

so the idea here is to just allow allowed clients to talk to the server. the token is digitally signed by the server before handing it out. all subsequent requests must have this

Ashley Smith15:08:27

my understanding is that a token is like a temporary password. You sign in and you get given a token for your use of the site. When you request data you use your token - but if everything is self contained on the server, what does the client get from signing in, and how is the server stateless if it is actually managing the currently active tokens

Ashley Smith15:08:41

So the token is still given out?

dharrigan15:08:49

https://jwt.io/ is a good start for understanding jwt

lispyclouds15:08:55

if the client has valid creds

ghadi15:08:12

the user ID is contained directly in the token information, and as long as the token is signed by the server, the server can trust its own signatures

4
Ashley Smith15:08:11

yeah, I'll go watch some videos that people have recommended as it seems these kinds of guides expect a basic understanding of the terminology otherwise I'll fail to understand the details like we just discussed. When it said everything is self contained. I was thinking it was referring to the server, not the token. Okay I get it

Ashley Smith15:08:19

Thank you for giving me a head start!

4
ghadi15:08:45

JSON web tokens are controversial

☝️ 4
ghadi15:08:06

Read about the controversy, it will prevent accidents 🙂

ghadi15:08:48

But you can ignore all of the specifics about JSON web tokens and think: encrypt(key, data_payload) == token

Ashley Smith15:08:06

controversial as in.. I shouldn't be learning to use them, or just that there has been and that its okay to use?

ghadi15:08:13

oh, sorry this is #clojure -- (let [token (encrypt key data)]...)

4
ghadi15:08:44

Depends on which security professional you talk to, but in the early days of JWTs, many of the libraries had terrible defaults.

ghadi15:08:17

Anything that tells you to make RSA openssl keys is suspect

ghadi15:08:41

you can use symmetric encryption to do these tokens ^^

ghadi15:08:08

all the backend servers will share the symmetric key -- which is another risk vector

ghadi15:08:16

do you know how many backends you'll have?

Ashley Smith15:08:19

That buddy page says this:

In order to use any asymmetric encryption algorithm, you should have private/public key pair. If you don’t have one, don’t worry, it is very easy to generate it using openssl, see this faq entry.
You think I should ignore that advice and do something else?

ghadi15:08:00

Nothing about this necessitates JWTs, or assymmetric encryption

Ashley Smith15:08:13

Hmm, no. In terms of types, I have a database server, my API server and my frontend server. In the future people might want multiple quantities of each but I'd have to learn docker swarms first. I'm taking it slow and doing one of each - but I don't know if I need new servers for this stuff

ghadi15:08:22

you type so fast, I'm impressed

ghadi15:08:32

conceptually, the server must be able to validate a token it is presented

ghadi15:08:55

can be signed with asymmetric encryption, or encrypted with a symmetric key

Ashley Smith15:08:58

Haha 🙂 I guess you could say I'm a little chatty because it's how I mainly learn - as you can probably gather from the amount of questions I ask here

Ashley Smith15:08:26

I also never take my fingers off the keyboard so I'm kind of just used to keybindings and doing things fairly quick

Ashley Smith15:08:31

Im eating lunch now though so taking it easy, then I'll watch those videos and have a shower while I think about my plan of attack

ghadi15:08:41

server receives and checks user/pw, returns to user (sign key {:user/id 42})

ghadi15:08:06

that's all a stateless token is

Ashley Smith15:08:56

Thank you very very much 🙂 I really cannot wait to get over this hurdle as its kind of the last big 'thing' I haven't touched, after this it should be game over 🙂

mjw16:08:27

If you use JWTs over session cookies for authentication, there are a couple things to look out for: - Server-side rendering just became impossible because JWTs stored in local/session storage have to be sent with an XHR request - If you provide downloads that require the user to be authenticated, you will have to either guarantee that downloads are small enough to use something like URL.createObjectURL in the browser, or you will have to generate short-lived, one-off URLs that do not require authentication - Local/session storage are not actually secure. If a JWT is stored in session storage, then entering sessionStorage in the Chrome dev tools will output all session storage tokens, making it possible to hijack a JWT from one user, call sessionStorage.setItem('{key}', '{other_users_jwt}') in dev tools for another session, and effectively be logged in as the first user. There are probably ways around this, but IMO it’s better to use session cookies.

👏 4
Ashley Smith16:08:00

thank you for the heads up!! 🙂

4
David Pham16:08:24

What is the state of a Clojure targeting .NET

andy.fingerhut16:08:20

It exists. David Miller does a lot of work on it to bring it up to date with features added to Clojure/Java version. According to Clojure surveys, it is used by a fairly small fraction of Clojure developers (about 2% of those who responded to 2019 survey). I personally have not used .NET for developing anything, Clojure or otherwise, so am not the right person to give more details.

David Pham17:08:21

Would it be safe to develop anything with it?

Alex Miller (Clojure team)17:08:06

depends how you measure safety :)

Alex Miller (Clojure team)17:08:22

afaik it works and is a reasonable close port of the jvm version

Alex Miller (Clojure team)17:08:00

the number of users is quite small though. the arcadia unity project is easily the biggest thing I know of based on it

Alex Miller (Clojure team)17:08:13

(I do not know of anything else)

David Pham17:08:09

Do you think support will drop at some point?

johnjelinek18:08:26

@seancorfield: I'm using depstar along with a process to do AOT in preparation to create a native-image with the GraalVM.

johnjelinek18:08:30

{:deps {org.clojure/clojure {:mvn/version "1.10.1"}}
 :aliases {:aot {:extra-paths ["classes"]
                 :main-opts ["-e" "(compile,'clj-graalvm.core)"]}
           :depstar {:extra-deps {seancorfield/depstar {:mvn/version "0.3.1"}}}}}
and I can generate the jar with:
clojure -A:depstar:aot -m hf.depstar.uberjar clj-graalvm.jar -m clj_graalvm.core -v
and run it:
java -jar clj-graalvm.jar
👋 1.10.1
but, I can't produce a native-image:
native-image --report-unsupported-elements-at-runtime --initialize-at-build-time -jar clj-graalvm.jar
Build on Server(pid: 41171, port: 57235)
[clj-graalvm:41171]    classlist:   1,114.78 ms
[clj-graalvm:41171]        (cap):     942.79 ms
[clj-graalvm:41171]        setup:   1,165.54 ms
[clj-graalvm:41171]     analysis:   4,439.00 ms
Warning: Aborting stand-alone image build. Class initialization of clj_graalvm.core failed. Use the option --initialize-at-run-time=clj_graalvm.core to explicitly request delayed initialization of this class.
Detailed message:

Warning: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
Build on Server(pid: 41171, port: 57235)
[clj-graalvm:41171]    classlist:     139.48 ms
[clj-graalvm:41171]        (cap):     927.01 ms
[clj-graalvm:41171]        setup:   1,141.24 ms
[clj-graalvm:41171]   (typeflow):   1,248.20 ms
[clj-graalvm:41171]    (objects):   1,359.97 ms
[clj-graalvm:41171]   (features):     104.56 ms
[clj-graalvm:41171]     analysis:   2,760.68 ms
[clj-graalvm:41171]     (clinit):      67.37 ms
[clj-graalvm:41171]     universe:     142.82 ms
[clj-graalvm:41171]      (parse):     218.14 ms
[clj-graalvm:41171]     (inline):     542.06 ms
[clj-graalvm:41171]    (compile):   1,023.42 ms
[clj-graalvm:41171]      compile:   1,923.44 ms
[clj-graalvm:41171]        image:     213.90 ms
[clj-graalvm:41171]        write:     130.16 ms
[clj-graalvm:41171]      [total]:   6,488.63 ms
Warning: Image 'clj-graalvm' is a fallback image that requires a JDK for execution (use --no-fallback to suppress fallback image generation).

ghadi19:08:02

native-image and clojure 1.10.1 are not compatible @johnjelinek

johnjelinek19:08:41

which version should I be using?

ghadi19:08:14

dunno - ask in #graalvm

ghadi19:08:06

has nothing to do with depstar

ghadi19:08:07

native-image is some weird relative to the JVM, doesn't support full Java

johnjelinek19:08:04

I just wanna make a few simple single-binary non-JVM CLI apps

Santiago20:08:02

I’m having difficulties making a multipart POST request with http-kit to the google drive rest api. Everything works with Postman, but I can’t figure out the configuration with http-kit/post or http-kit/request. Has anyone done this?

telekid20:08:55

I’m working on a PR for a library, and I’d like to test it locally in a different deps.edn project. However, I can’t quite figure out what the best way to require the local copy. Are people using deps :aliases for that?

telekid20:08:39

I’ve tried the :alias approach, but the library is a lein project and I’m getting Manifest type not detected when finding deps

telekid20:08:49

not sure how to resolve

telekid20:08:01

Ah, I just needed to run lein pom

jaihindhreddy22:08:14

What's the difference b/w vars and atoms?

jaihindhreddy22:08:07

How is alter-var-root diff. from swap!, except from the retry in the atom case?

jaihindhreddy22:08:46

What happens when multiple threads try to alter a var root and fail?

noisesmith22:08:13

alter-var-root doesn't fail AFAIK, it's just serialized?

noisesmith22:08:13

swap! is faster if lack of contention is the common case

noisesmith22:08:26

alter-var-root just locks while updating so the contender has to wait

noisesmith22:08:43

it's slower thanks to the lock (which an atom doesn't need)

seancorfield22:08:18

@jaihindhreddy have you read this page? https://clojure.org/reference/vars it tries to explain how var differs from the other mutable types (I thought it explained all four but they're spread across multiple pages)

jaihindhreddy22:08:11

Read this page and the atom page before posting here but still didn't get it. Now I understand that alter-var-root locks the var whereas atom leverages CAS with retries.

seancorfield22:08:47

There's also the per-thread dynamic aspect of vars

noisesmith22:08:44

alter-var-root calls out to this, which thanks to synchronized uses locking implicitly https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L307

👍 4
noisesmith22:08:54

swap! calls this, no locking or synchronization (uses compareAndSet and retries until success instead) https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Atom.java#L33

💯 4
johnjelinek22:08:49

@seancorfield: I'm using https://github.com/clojure/tools.cli and encountering interesting behavior:

(defn default-repository-name []
  (->> (clojure.string/split (-> (java.io.File. ".") .getAbsolutePath) #"/")
       reverse
       second))
I was expecting that if I ran my application from different locations, then the default would render differently:
$ pwd
/vault-policy-generator/wat

$ ../vault-policy-generator -h
This reviews your repository and spits out appropriate vault policies.

Usage: vault-policy-generator [options]

Options:
  -d, --database NAME                          Database Name
  -n, --name NAME      vault-policy-generator  Repository name
  -h, --help
I was expecting it to say -n, --name NAME wat Repository name ☝️
(def cli-options
  [["-d" "--database NAME" "Database Name (web or pos)"]
   ["-n" "--name NAME" "Repository name"
    :default (default-repository-name)]
   ["-h" "--help"]])

seancorfield22:08:40

@johnjelinek you built an uberjar?

seancorfield22:08:22

(With AOT I'm guessing)

seancorfield22:08:52

def computes the value at compile time

seancorfield22:08:22

So AOT compiles it and that's the value it gets for all time.

johnjelinek22:08:55

What's the right way to tell to to come up with this value at runtime?

seancorfield22:08:04

Build the uberjar WITHOUT AOT and it will do what you want

seancorfield22:08:22

But then you'll need to run it differently

seancorfield22:08:00

(I'm on vacation in England so I'm typing on my phone -- explanation is limited 😁)

😮 4
johnjelinek22:08:05

Is there a way to keep AOT and still allow this to be evaluated at runtime?

johnjelinek22:08:31

OH! 😆 we don't have to figure this out right now, go vacation!

seancorfield22:08:01

Make it a defn with no args and call it

seancorfield22:08:42

At work we just don't use AOT at all

johnjelinek22:08:49

OH! 😆 good catch!

johnjelinek22:08:02

😆 that's why I'm in #beginners