Coder Social home page Coder Social logo

clj-jwt's Introduction

clj-jwt's People

Contributors

aew avatar deliminator avatar jonasabreu avatar liquidz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clj-jwt's Issues

Handling of Clojure maps in JWT claims

Clojure maps are serialized differently into JSON object, depending on underlying map implementation (clojure.lang.PersistentHashMap or clojure.lang.PersistentArrayMap) or hash function (which has changed in Clojure 1.6).
Since result JSON can be different — computed signatures can be different for token issuer and receiver, and whole authentication fails.
I think that clj-jwt should always serialize map in the same way, not depending on its implementation.

Problem `NoClassDefFoundError` for class `Encodable` from bouncycastle.

Hi

I've been using your library quite extensively and just recently I've run into a problem when attempting to upgrade the dependencies in an older project.

I'm using the latest version of clj-jwt, i.e. 1.1, with Clojure 1.7.0 etc..

I'm getting this warning, which I've not seen before:

java.lang.NoClassDefFoundError: org/bouncycastle/util/Encodable, compiling:(key.clj:1:1)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3628)
    at clojure.lang.Compiler.compile1(Compiler.java:7323)
    at clojure.lang.Compiler.compile1(Compiler.java:7313)
    at clojure.lang.Compiler.compile(Compiler.java:7390)
    at clojure.lang.RT.compile(RT.java:399)
    at clojure.lang.RT.load(RT.java:444)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)

I notice that bouncycastle is a dependency and it should be in the jar already.

If I manually include it as a dependency in my project.clj file, like this:

[org.bouncycastle/bcpkix-jdk15on "1.52"

then I get a different error:

java.lang.SecurityException: class "org.bouncycastle.asn1.x509.TBSCertificate"'s signer information does not match signer information of other classes in the same package, compiling:(clj_jwt/key.clj:37:22)

Can you give me a hint as to why I can't resolve this dependency anymore?

Cheers, Jason.

Using a secret key to verify an unsigned token returns true, probable security issue

I have found that it is possible for the verify function to return a positive result in cases where the token should not be considered validly signed, for example, if the token is not signed in the first place and is being verifyed with a secret key.

Example:

(def claim {:iss "foo"})

;; Verify a signed token, using our secret
(-> claim jwt (sign :HS384 "foo") to-str str->jwt (verify "foo")) ;; => true

;; Verify an UNSIGNED token
(-> claim jwt                     to-str str->jwt (verify "foo")) ;; => true

Logically, the second example should produce the value false, as it is impossible for the token to be valid with our secret if it was never signed with that secret, or any other secret to begin with.

I think this is happening because the verify function ignores the supplied key value entirely if the token is unsigned.

I have prepared a patch here which fixes the immediate issue, and I will submit a pull-request soon. I would however recommend a full audit of this code-path and its test-suite to ensure the tokens are being signed and validated securely.

exception using cipher - please check password and data

Running the below code causes the following error. The code with the respective keys work perfectly fine on my Linux machine, however, switching to my Mac and running my code causes the error.

(def rsa-prv-key (private-key (str rsa-path "private.pem") rsa-pass))
Exception in thread "main" org.bouncycastle.openssl.EncryptionException: exception using cipher - please check password and data., compiling:(util.clj:10:18)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3558)
    at clojure.lang.Compiler$DefExpr.eval(Compiler.java:417)
    at clojure.lang.Compiler.eval(Compiler.java:6708)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:436)
    at messenger_server.routes.app_routes$eval8513$loading__4958__auto____8514.invoke(app_routes.clj:1)
    at messenger_server.routes.app_routes$eval8513.invoke(app_routes.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6692)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:482)
    at messenger_server.routes.master$eval6919$loading__4958__auto____6920.invoke(master.clj:1)
    at messenger_server.routes.master$eval6919.invoke(master.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6692)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:619)
    at messenger_server.handler$eval169$loading__4958__auto____170.invoke(handler.clj:1)
    at messenger_server.handler$eval169.invoke(handler.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6692)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at messenger_server.core$eval20$loading__4958__auto____21.invoke(core.clj:1)
    at messenger_server.core$eval20.invoke(core.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6692)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at user$eval5$fn__7.invoke(form-init1974931039856357505.clj:1)
    at user$eval5.invoke(form-init1974931039856357505.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.bouncycastle.openssl.EncryptionException: exception using cipher - please check password and data.
    at org.bouncycastle.openssl.PEMUtilities.crypt(Unknown Source)
    at org.bouncycastle.openssl.PEMUtilities.crypt(Unknown Source)
    at org.bouncycastle.openssl.PEMReader$KeyPairParser.readKeyPair(Unknown Source)
    at org.bouncycastle.openssl.PEMReader$RSAKeyPairParser.parseObject(Unknown Source)
    at org.bouncycastle.openssl.PEMReader.readObject(Unknown Source)
    at clj_jwt.key$pem__GT_key.invoke(key.clj:16)
    at clj_jwt.key$private_key.doInvoke(key.clj:23)
    at clojure.lang.RestFn.applyTo(RestFn.java:139)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3553)
    ... 124 more
Caused by: javax.crypto.BadPaddingException: pad block corrupted
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
    at javax.crypto.Cipher.doFinal(Cipher.java:2121)
    ... 133 more

decode HMAC256 signed token

Hi, I think I'm missing something important because I don't understand how I can decode my signed token without the secret.
(-> token str->jwt :claims :iss)

I always need to verify first ?

str->jwt throws exceptions

From the perspective of the application, str->jwt is part of the verification process. Currently it throws exceptions when given an invalid string. I don't think it's the responsibility of the application to catch these exceptions. What I'm asking may involve an API change, it's up to you if you want to do that. Just documenting this behavior would be good too.

Thank you for your work.

Support for decoding tokens

Is there support for decoding tokens? If so, are there any docs for it? I have searched and searched for it and have found no such docs or functionality.

date values for :exp :nbf and :iat are divided by 1000?

I ran into a bit of a problem with clj-jwt today, when I decided to add an :exp field to the claims set that I had been experimenting with.

Adding the :exp field seemed to work fine, and the resulting token contained an exp value with a long/int type, as I would have expected. However, when I used clj-time.coerce.from-long on the exp value, I got a strange date back, some time in 1970.
I would have expected that from-long would produce the original date (and then be able to check that against the current time, etc)

After a bit of digging around I found that line14 of clj_jwt/core.clj defines a to-intdate function as:

(defn- to-intdate [d] {:pre [(joda-time? d)]} (int (/ (to-long d) 1000)))

The division by 1000 on the result of the to-long call strikes me as odd, as it means that the user of the library must manually multiply these date ints by 1000 before trying to get a date object back from them, Example:

(defn token-valid? [decoded-token]
  (let [exp-int (get-in decoded-token [:claims :exp])
        exp (from-long (* 1000 exp-int))
        nbf-int (get-in decoded-token [:claims :nbf])
        nbf (from-long (* 1000 nbf-int))
        current-time (now)]
    (and (not (before? exp current-time))
            (not (after? nbf current-time)))))

Is there a reason why the dates need to be divided by 1000 before being stored in the token? If so then the fact should be documented, as the current behaviour can be quite surprising. Either way, I would be willing to take up the work of either improving the documentation or patching the behaviour.

Thanks.

EDIT: It's also possible that I'm missing something here, and that it's not actually necessary to manually inspect the exp and nbf fields when checking the token, any guidance on that would be appreciated

No implementation of method :init for class JWT

I admit this is bizarre, but I tried to update to 0.0.12 and got following error on a call to (jwt claims):

java.lang.IllegalArgumentException: No implementation of method: :init of protocol: #'clj-jwt.core/JsonWebToken found for class: clj_jwt.core.JWT
          core_deftype.clj:544 clojure.core/-cache-protocol-fn
                   core.clj:22 clj-jwt.core/eval3008[fn]
                   core.clj:82 clj-jwt.core/jwt

I tested this on the repl with 0.0.12 and 0.0.11 before dropping back to 0.0.6, where it works. I'm rather confused by this, since you clearly implement the protocol in your code. So if you know what the problem is, I'd be glad to know and then close this issue.

Same iat for multiple requests

Hi,

I found that multiple requests have same iat (it's wrong), due coercing from long to int.
What is a reason for coercing?

Thanks

IllegalArgumentException No matching method found: initVerify for class java.security.Signature$Delegate clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

IllegalArgumentException No matching method found: initVerify for class java.security.Signature$Delegate clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

(-> "eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiIwYjQ4Y2M0ZmEzMDY0ZDIwOTRhNDUwYWYwZmUyYTZiZSIsInN1YiI6ImZyYW1ld29yay1jbGllbnQiLCJzY29wZSI6WyJhbmFseXRpY3Muem9uZXMuYmY3NDIwZDAtYmY2NC00ZmYwLWJhZWYtNmQzNjJjYjA1YjMzLnVzZXIiLCJwcmVkaXgtYXNzZXQuem9uZXMuOTQyNzkxZGQtM2EwMC00NTE2LWE0NzUtNTc5NjBiOTRkYzk3LnVzZXIiLCJ0aW1lc2VyaWVzLnpvbmVzLjhkOTU2YWIxLWE5NzgtNDA2Zi1hYTEzLWE1YTY3ODc5Y2JkNC5xdWVyeSIsIm9wZW5pZCIsInVhYS5ub25lIiwidGltZXNlcmllcy56b25lcy44ZDk1NmFiMS1hOTc4LTQwNmYtYWExMy1hNWE2Nzg3OWNiZDQuaW5nZXN0IiwidGltZXNlcmllcy56b25lcy44ZDk1NmFiMS1hOTc4LTQwNmYtYWExMy1hNWE2Nzg3OWNiZDQudXNlciIsInVhYS51c2VyIl0sImNsaWVudF9pZCI6ImZyYW1ld29yay1jbGllbnQiLCJjaWQiOiJmcmFtZXdvcmstY2xpZW50IiwiYXpwIjoiZnJhbWV3b3JrLWNsaWVudCIsImdyYW50X3R5cGUiOiJjbGllbnRfY3JlZGVudGlhbHMiLCJyZXZfc2lnIjoiOTcxNmNhMWMiLCJpYXQiOjE1MDA5MzU4NDYsImV4cCI6MTUwMDk3OTA0NiwiaXNzIjoiaHR0cHM6Ly9jNTZjMTE0OC0xOWY3LTRkODAtYjFhMi1jZDliMTk5MDBmNDYucHJlZGl4LXVhYS5ydW4uYXdzLXVzdzAyLXByLmljZS5wcmVkaXguaW8vb2F1dGgvdG9rZW4iLCJ6aWQiOiJjNTZjMTE0OC0xOWY3LTRkODAtYjFhMi1jZDliMTk5MDBmNDYiLCJhdWQiOlsicHJlZGl4LWFzc2V0LnpvbmVzLjk0Mjc5MWRkLTNhMDAtNDUxNi1hNDc1LTU3OTYwYjk0ZGM5NyIsImFuYWx5dGljcy56b25lcy5iZjc0MjBkMC1iZjY0LTRmZjAtYmFlZi02ZDM2MmNiMDViMzMiLCJ1YWEiLCJ0aW1lc2VyaWVzLnpvbmVzLjhkOTU2YWIxLWE5NzgtNDA2Zi1hYTEzLWE1YTY3ODc5Y2JkNCIsIm9wZW5pZCIsImZyYW1ld29yay1jbGllbnQiXX0.pu3i6FYH_CAQ6DOglv_OtJqTauuTKYSNfnrLCSSVPrgwQ-Qa60JsilMTMDuXMaqOEcAVZvlt1U_rrMiaDErj9jf_jkMT0-f8pWJP5Kai3mGjOpSJJCW4PgNErRI_N0jFznbohV-7hyhh4S7rsScCregPq1BqufkKDrhyrnbXhkATGvtlNb5vgaV8FWRG-AcXWQFavzlz_oKpduMBVJcwu7WcReh75va9cbNT8l75Ri4CPt_E20xOwsgqIRgOZhb8H-8RKYjMsW-2eHxNsVlzHswWDvSdgSiJqJtwW56HrSlK4ooCBhgGNkeyVs6Q7B_rIBgLw-EgxTyZDTTtiNTbgQ" 
                                      clj-jwt/str->jwt
                                      (clj-jwt/verify "AMYxBBzSwaNlJwixok3_6ayAB5sIcOaAvklhfm4dsRowquL49jK0SrxyMz1_aV2c5p_obWoSFtvEaDWsx4rYK8K1q_uq324DQ4ENW9TeO6gYmc60cc4HGRUcdjnz_DAV7bwU-7V5QCYXRFpSVlHxrQpbjxuPUc-EneJ2qBhJXaQCkNCNhIo1QhkIdb7RDngOaXzwkn4TvQPw5U-5JeHbKLXU6HBvcw4RpsdPpGkolfavrKPUZ5kiVoC5TPuSmpSshRaCtz0YHC7IzH_gxCw-xd10zZ4BU418MvghV21grAIey_Dng3YvSuOdm2_CQyof2faQbT_NDwZUhT9DQKwFMU0="))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.