首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用Midje伪造朋友凭证函数

利用Midje伪造朋友凭证函数
EN

Stack Overflow用户
提问于 2014-11-14 08:08:58
回答 2查看 210关注 0票数 1

我正试图用Midje单独测试我的路由。对于一些访问数据库的路由,我可以使用(provided ...)将路由与真正的db调用隔离开来。我已经介绍了一个用于身份验证的朋友,并且我无法伪造对凭证函数的调用。

我的凭据函数看起来如下(它是这样实现的,因为我还不希望它被调用):

代码语言:javascript
复制
(defn cred-fn
  [creds]
  (println (str "hey look I got called with " creds))
  (throw (Exception.)))

然后,用于路由的中间件如下所示:

代码语言:javascript
复制
(def app 
  (-> app-routes
      (wrap-json-body {:keywords? true :bigdecimals? true})
      wrap-json-response
      (wrap-defaults defaults)
      (friend/authenticate
       {:unauthorized-handler json-auth/login-failed
        :workflows [(json-auth/json-login
                     :login-uri "/login"
                     :login-failure-handler json-auth/login-failed
                     :credential-fn auth/cred-fn)]})
      (ring-session/wrap-session)))

我也尝试过没有使用auth工作流,路由的实现看起来几乎是一样的,如果它有帮助的话,我可以添加它,但是我得到了相同的结果。

然后,我的测试看起来如下(使用环模拟):

代码语言:javascript
复制
(defn post [url body]
  (-> (mock/request :post url body)
      (mock/content-type "application/json")
      app))

(fact "login with incorrect username and password returns unauthenticated"
  (:status (post "/login" invalid-auth-account-json)) => 401
  (provided
    (auth/cred-fn anything) => nil))
(fact "login with correct username and password returns success"
  (:status (post "/login" auth-account-json)) => 200
  (provided
    (auth/cred-fn anything) => {:identity "root"}))

然后,我得到以下运行测试的输出:

代码语言:javascript
复制
hey look I got called with {:password "admin_password", :username "not-a-user"}
FAIL at (handler.clj:66)
These calls were not made the right number of times:
    (auth/cred-fn anything) [expected at least once, actually never called]
FAIL "routes - authenticated routes - login with incorrect username and password returns unauthenticated" at (handler.clj:64)
    Expected: 401
      Actual: java.lang.Exception
          clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)

hey look I got called with {:password "admin_password", :username "root"}
FAIL at (handler.clj:70)
These calls were not made the right number of times:
    (auth/cred-fn anything) [expected at least once, actually never called]

FAIL "routes - authenticated routes - login with correct username and password returns success" at (handler.clj:68)
    Expected: 200
      Actual: java.lang.Exception
          clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)

因此,从我所看到的情况来看,所提供的语句没有生效,我也不知道为什么。有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-02 23:10:46

我最近遇到了一个类似的问题,经过一番调查,我想我理解了为什么会发生这种情况。让我们看看auth/cred-fn的绑定是如何随时间变化的。

代码语言:javascript
复制
(clojure.pprint/pprint (macroexpand '(defn cred-fn
                                                [creds]
                                                (println (str "hey look I got called with " creds))
                                                (throw (Exception.)))))
(def
 cred-fn
 (clojure.core/fn
  ([creds]
   (println (str "hey look I got called with " creds))
   (throw (Exception.)))))

如上文所示,defn宏在当前命名空间中实习生符号cred-fn,并将其绑定到引用虚拟函数的Var。

代码语言:javascript
复制
(def app 
    (-> app-routes
        (wrap-json-body {:keywords? true :bigdecimals? true})
        wrap-json-response
        (wrap-defaults defaults)
        (friend/authenticate
        {:unauthorized-handler json-auth/login-failed
        :workflows [(json-auth/json-login
                    :login-uri "/login"
                    :login-failure-handler json-auth/login-failed
                    :credential-fn auth/cred-fn)]})
        (ring-session/wrap-session)))

这是最重要的部分。在编译时,我们通过一系列函数线程app-routes。其中一个函数是friend/authenticate,它使用带有键:workflows的映射。:workflows的值是一个向量,其中填充了对json-auth/json-login的调用结果,后者接收auth/credential-fn作为参数。记住,我们在一个def中,所以这一切都是在编译时发生的。我们在auth命名空间中查找符号cred-fn,并传入符号绑定到的Var。在这一点上,这仍然是虚拟实现。想必,json-auth/json-login捕获这个实现并设置一个请求处理程序来调用它。

代码语言:javascript
复制
(fact "login with incorrect username and password returns unauthenticated"
    (:status (post "/login" invalid-auth-account-json)) => 401
    (provided
    (auth/cred-fn anything) => nil))

现在我们在运行时。在我们的前提条件下,Midje将符号auth/cred-fn重新绑定到引用模拟的Var。但是,当我们在编译时使用auth/cred-fn d app时,已经捕获了app的值。

那么,你发布的解决方案是怎么做到的呢?(这实际上是我来到尤里卡时刻的线索--谢谢你。)

代码语言:javascript
复制
(defn another-fn []
  (println (str "hey look I got called"))
  (throw (Exception.)))

(defn cred-fn [creds]
  (another-fn))

在你的测试中..。

代码语言:javascript
复制
(fact "login with incorrect username and password returns unauthenticated"
  (:status (post "/login" invalid-auth-account-json)) => 401
  (provided
    (auth/another-fn) => nil))

(fact "login with correct username and password returns success"
  (:status (post "/login" auth-account-json)) => 200
  (provided
    (auth/another-fn) => {:identity "root"}))

这是因为,在编译时,捕获的auth/cred-fn值是一个简单地委托给auth/another-fn的函数。请注意,尚未对auth/another-fn进行评估。现在,在我们的测试中,Midje重新绑定auth/another-fn以引用模拟。然后执行post,在中间的某个地方调用auth/cred-fn。在auth/cred-fn中,我们查找绑定到auth/another-fn (这是我们的模拟)的Var,并调用它。当然,现在的行为和你第一次所期望的完全一样。

这个故事的寓意是,be 小心Clojure中的def

票数 1
EN

Stack Overflow用户

发布于 2014-11-14 15:05:18

我还是不知道为什么会这样,但我有工作要做。如果我将我的credential-fn替换为:

代码语言:javascript
复制
(defn another-fn
  []
  (println (str "hey look I got called"))
  (throw (Exception.)))

(defn cred-fn
  [creds]
  (another-fn))

然后为测试中的新函数创建一个伪函数,如下所示:

代码语言:javascript
复制
(fact "login with incorrect username and password returns unauthenticated"
  (:status (post "/login" invalid-auth-account-json)) => 401
  (provided
    (auth/another-fn) => nil))

(fact "login with correct username and password returns success"
  (:status (post "/login" auth-account-json)) => 200
  (provided
    (auth/another-fn) => {:identity "root"}))

我得到了我期待的结果。cred-fn仍然会被调用,但是another-fn不会因为provided而被调用。

如果有人知道为什么我会有兴趣知道的话。这可能是因为凭证函数被调用的方式?- workflow.clj#L46

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26925557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档