<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 06/10/2014 09:27 PM, Aline Manera
      wrote:<br>
    </div>
    <blockquote cite="mid:539707BD.2080807@linux.vnet.ibm.com"
      type="cite">On 06/10/2014 09:42 AM, Sheldon wrote:
      <br>
      <blockquote type="cite">On 06/10/2014 02:11 AM, Aline Manera
        wrote:
        <br>
        <blockquote type="cite">On 06/05/2014 01:10 PM,
          <a class="moz-txt-link-abbreviated" href="mailto:shaohef@linux.vnet.ibm.com">shaohef@linux.vnet.ibm.com</a> wrote:
          <br>
          <blockquote type="cite">From: ShaoHe Feng
            <a class="moz-txt-link-rfc2396E" href="mailto:shaohef@linux.vnet.ibm.com">&lt;shaohef@linux.vnet.ibm.com&gt;</a>
            <br>
            <br>
            If the content type is application/json still raise 401
            status code.
            <br>
            And let UI redirect to login page.
            <br>
            <br>
            or the backe redirects to login page directly.
            <br>
            <br>
            Signed-off-by: ShaoHe Feng
            <a class="moz-txt-link-rfc2396E" href="mailto:shaohef@linux.vnet.ibm.com">&lt;shaohef@linux.vnet.ibm.com&gt;</a>
            <br>
            Signed-off-by: Yu Xin Huo
            <a class="moz-txt-link-rfc2396E" href="mailto:huoyuxin@linux.vnet.ibm.com">&lt;huoyuxin@linux.vnet.ibm.com&gt;</a>
            <br>
            ---
            <br>
            src/kimchi/auth.py | 11 +++++++++++
            <br>
            src/kimchi/config.py.in | 3 +++
            <br>
            src/kimchi/root.py | 28 +++++++++++++++++++---------
            <br>
            ui/js/src/kimchi.main.js | 5 +----
            <br>
            4 files changed, 34 insertions(+), 13 deletions(-)
            <br>
            <br>
            diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py
            <br>
            index dc78ded..a38dbd3 100644
            <br>
            --- a/src/kimchi/auth.py
            <br>
            +++ b/src/kimchi/auth.py
            <br>
            @@ -28,6 +28,7 @@
            <br>
            import re
            <br>
            import termios
            <br>
            import time
            <br>
            +import urllib2
            <br>
            <br>
            <br>
            from kimchi import template
            <br>
            @@ -41,6 +42,12 @@
            <br>
            REFRESH = 'robot-refresh'
            <br>
            <br>
            <br>
            +def redirect_login():
            <br>
            + next_url = urllib2.quote(
            <br>
            + cherrypy.request.path_info.encode('utf-8'), safe="")
            <br>
            + raise cherrypy.HTTPRedirect("/login.html?next=%s" %
            next_url, 303)
            <br>
            +
            <br>
            +
            <br>
            def debug(msg):
            <br>
            pass
            <br>
            # cherrypy.log.error(msg)
            <br>
            @@ -234,6 +241,10 @@ def kimchiauth(admin_methods=None):
            <br>
            raise cherrypy.HTTPError(403)
            <br>
            return
            <br>
            <br>
            + # not a REST full request, redirect login page directly
            <br>
            + if not template.can_accept('application/json'):
            <br>
            + redirect_login()
            <br>
            +
            <br>
            if not from_browser():
            <br>
            cherrypy.response.headers['WWW-Authenticate'] = 'Basic
            realm=kimchi'
            <br>
            <br>
            diff --git a/src/kimchi/config.py.in
            b/src/kimchi/config.py.in
            <br>
            index 0206570..d4cbda0 100644
            <br>
            --- a/src/kimchi/config.py.in
            <br>
            +++ b/src/kimchi/config.py.in
            <br>
            @@ -187,6 +187,9 @@ class KimchiConfig(dict):
            <br>
            '/spice.html': {
            <br>
            'tools.kimchiauth.on': True
            <br>
            },
            <br>
            + '/kimchi-ui.html': {
            <br>
            + 'tools.kimchiauth.on': True
            <br>
            + },
            <br>
            '/data/screenshots': {
            <br>
            'tools.staticdir.on': True,
            <br>
            'tools.staticdir.dir': get_screenshot_path(),
            <br>
            diff --git a/src/kimchi/root.py b/src/kimchi/root.py
            <br>
            index 8b1d09b..181ab13 100644
            <br>
            --- a/src/kimchi/root.py
            <br>
            +++ b/src/kimchi/root.py
            <br>
            @@ -81,7 +81,7 @@ def get(self):
            <br>
            @cherrypy.expose
            <br>
            def default(self, page, **kwargs):
            <br>
            if page.endswith('.html'):
            <br>
            - return template.render(page, None)
            <br>
            + return template.render(page, kwargs)
            <br>
            raise cherrypy.HTTPError(404)
            <br>
            <br>
            @cherrypy.expose
            <br>
            @@ -110,14 +110,24 @@ def __init__(self, model, dev_env):
            <br>
            self.messages = messages
            <br>
            <br>
            @cherrypy.expose
            <br>
            - def login(self, *args):
            <br>
            - params = parse_request()
            <br>
            - try:
            <br>
            - username = params['username']
            <br>
            - password = params['password']
            <br>
            - except KeyError, item:
            <br>
            - e = MissingParameter('KCHAUTH0003E', {'item': str(item)})
            <br>
            - raise cherrypy.HTTPError(400, e.message)
            <br>
          </blockquote>
          <br>
          <blockquote type="cite">+ def login(self, *args, **kwargs):
            <br>
            + username = kwargs.get('username')
            <br>
            + password = kwargs.get('password')
            <br>
            + # forms base authentication
            <br>
            + if username is not None:
            <br>
            + # UI can pass the redirect url by "next" query parameter
            <br>
            + next_url = kwargs.get('next', "/")
            <br>
            + next_url = type(next_url) is list and next_url[0]
            <br>
            + auth.login(username, password)
            <br>
            + raise cherrypy.HTTPRedirect(next_url, 303)
            <br>
            + else:
            <br>
            + try:
            <br>
            + params = parse_request()
            <br>
            + username = params['username']
            <br>
            + password = params['password']
            <br>
            + except KeyError, item:
            <br>
            + e = MissingParameter('KCHAUTH0003E', {'item': str(item)})
            <br>
            + raise cherrypy.HTTPError(400, e.message)
            <br>
          </blockquote>
          <br>
          I didn't understand this code.
          <br>
          Why did you get username and password from kwargs and in
          "else" from parse_request()?
          <br>
          Should that info be in a single location?
          <br>
        </blockquote>
        parse_request() get the password and username from body for REST
        API request.
        <br>
        for form authentication. The cherrypy will do it by itself, and
        pass it to login
        <br>
      </blockquote>
      <br>
      And when in which situation we get the username and password from
      kwargs?
      <br>
      <br>
      PS. Sorry about too many questions but I am trying to understand
      the code =)
      <br>
    </blockquote>
    <br>
    <div class="netInfoHeadersGroup netInfoRequestHeadersTitle "><span
        class=" ">Request Headers</span><span
        class="netHeadersViewSource request ">view source</span></div>
    <table class=" " cellpadding="0" cellspacing="0">
      <tbody role="list" aria-label="Request Headers"
        class="netInfoRequestHeadersBody ">
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Accept</span></td>
          <td role="list" aria-label="Accept" class="netInfoParamValue "><code
              aria-selected="true" tabindex="0" role="listitem"
              class="focusRow subFocusRow a11yModified">text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Accept-Encoding</span></td>
          <td role="list" aria-label="Accept-Encoding"
            class="netInfoParamValue "><code aria-selected="false"
              tabindex="-1" role="listitem" class="focusRow subFocusRow
              a11yModified">gzip, deflate</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Accept-Language</span></td>
          <td role="list" aria-label="Accept-Language"
            class="netInfoParamValue "><code role="listitem"
              class="focusRow subFocusRow ">zh-cn,en-us;q=0.7,en;q=0.3</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Connection</span></td>
          <td role="list" aria-label="Connection"
            class="netInfoParamValue "><code role="listitem"
              class="focusRow subFocusRow ">keep-alive</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Cookie</span></td>
          <td role="list" aria-label="Cookie" class="netInfoParamValue "><code
              role="listitem" class="focusRow subFocusRow ">userid=root;
              kimchiLang=zh_CN; username=shhfeng; ticketVM=VqO6AWlH;
              lastPage="/#tabs/templates"; kimchi</code><code
              aria-selected="false" tabindex="-1" role="listitem"
              class="focusRow subFocusRow a11yModified">=fc2fa059ee694c3d959fa1a1902557d21526e78e</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">DNT</span></td>
          <td role="list" aria-label="DNT" class="netInfoParamValue "><code
              role="listitem" class="focusRow subFocusRow ">1</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Host</span></td>
          <td role="list" aria-label="Host" class="netInfoParamValue "><code
              role="listitem" class="focusRow subFocusRow ">localhost:8001</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Referer</span></td>
          <td role="list" aria-label="Referer" class="netInfoParamValue
            "><code role="listitem" class="focusRow subFocusRow "><a class="moz-txt-link-freetext" href="https://localhost:8001/login.html">https://localhost:8001/login.html</a></code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">User-Agent</span></td>
          <td role="list" aria-label="User-Agent"
            class="netInfoParamValue "><code role="listitem"
              class="focusRow subFocusRow ">Mozilla/5.0 (X11; Linux
              x86_64; rv:29.0) Gecko/20100101 Firefox/29.0</code></td>
        </tr>
      </tbody>
    </table>
    <table class=" " cellpadding="0" cellspacing="0">
      <tbody role="list" aria-label="Response Headers From Cache"
        class="netInfoCachedResponseHeadersBody ">
      </tbody>
    </table>
    <div class="netInfoHeadersGroup netInfoPostRequestHeadersTitle "><span
        class=" ">Request Headers From Upload Stream</span></div>
    <table class=" " cellpadding="0" cellspacing="0">
      <tbody role="list" aria-label="Request Headers From Upload Stream"
        class="netInfoPostRequestHeadersBody ">
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Content-Length</span></td>
          <td role="list" aria-label="Content-Length"
            class="netInfoParamValue "><code role="listitem"
              class="focusRow subFocusRow ">41</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">Content-Type</span></td>
          <td role="list" aria-label="Content-Type"
            class="netInfoParamValue "><code role="listitem"
              class="focusRow subFocusRow ">application/x-www-form-urlencoded</code></td>
        </tr>
      </tbody>
    </table>
    <br>
    <br>
    post body. <br>
    I think the cherrypy know <span class="netInfoPostContentType ">x-www-form-urlencoded,
      it can parser the body by itself. </span>  <br>
    <br>
    <table role="presentation" class="netInfoPostParamsTable "
      cellpadding="0" cellspacing="0">
      <tbody role="list" aria-label="Parameters" class=" ">
        <tr role="presentation" class="netInfoPostParamsTitle ">
          <td colspan="2" role="presentation" class=" ">
            <div class="netInfoPostParams ">Parameters<span
                class="netInfoPostContentType ">application/x-www-form-urlencoded</span></div>
          </td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">next</span></td>
          <td role="list" aria-label="next" class="netInfoParamValue "><code
              aria-selected="false" tabindex="-1" role="listitem"
              class="focusRow subFocusRow a11yModified">/</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">password</span></td>
          <td role="list" aria-label="password" class="netInfoParamValue
            "><code role="listitem" class="focusRow subFocusRow ">123456</code></td>
        </tr>
        <tr role="listitem" class=" ">
          <td role="presentation" class="netInfoParamName "><span
              class=" ">username</span></td>
          <td role="list" aria-label="username" class="netInfoParamValue
            "><code aria-selected="false" tabindex="-1" role="listitem"
              class="focusRow subFocusRow a11yModified">shhfeng</code></td>
        </tr>
      </tbody>
    </table>
    <table role="presentation" class="netInfoPostSourceTable "
      cellpadding="0" cellspacing="0">
      <tbody role="list" aria-label="Source" class=" ">
        <tr role="presentation" class="netInfoPostSourceTitle ">
          <td colspan="2" role="presentation" class=" ">
            <div class="netInfoPostSource ">Source</div>
          </td>
        </tr>
        <tr role="presentation" class=" ">
          <td colspan="2" role="presentation" class=" "><code
              aria-selected="true" tabindex="0" role="listitem"
              class="focusRow subFocusRow a11yModified">next=%2F&amp;username=shhfeng&amp;password=123456</code></td>
        </tr>
      </tbody>
    </table>
    <br>
    <br>
    By our rest quest,  the <span class=" ">Content-Type is
      application/json</span> we paser it by ourself.  <br>
    <br>
    <br>
    <font color="#3333ff">I have check the cherrypy code:  some
      explanation for application/x-www-form-urlencoded</font><br>
    <br>
        def _get_body_params(self):<br>
            warnings.warn(<br>
                    "body_params is deprecated in CherryPy 3.2, will be
    removed in "<br>
                    "CherryPy 3.3.",<br>
                    DeprecationWarning<br>
                )<br>
            return self.body.params<br>
        body_params = property(_get_body_params,<br>
                          doc= """<br>
        If the request Content-Type is
    'application/x-www-form-urlencoded' or<br>
        multipart, this will be a dict of the params pulled from the
    entity<br>
        body; that is, it will be the portion of request.params that
    come<br>
        from the message body (sometimes called "POST params", although
    they<br>
        can be sent with various HTTP method verbs). This value is set
    between<br>
        the 'before_request_body' and 'before_handler' hooks (assuming
    that<br>
        process_request_body is True).<br>
        <br>
        Deprecated in 3.2, will be removed for 3.3 in favor of<br>
       
:attr:`request.body.params&lt;cherrypy._cprequest.RequestBody.params&gt;`.""")<br>
    <br>
    <br>
    <blockquote cite="mid:539707BD.2080807@linux.vnet.ibm.com"
      type="cite">
      <blockquote type="cite">
        <blockquote type="cite">
          <br>
          And if you raise/return, you don't need a "else" it eliminates
          some indentation levels.
          <br>
        </blockquote>
        I can remove the “else”
        <br>
        <blockquote type="cite">
          <br>
          <blockquote type="cite">try:
            <br>
            user_info = auth.login(username, password)
            <br>
            diff --git a/ui/js/src/kimchi.main.js
            b/ui/js/src/kimchi.main.js
            <br>
            index 184029d..2a8f461 100644
            <br>
            --- a/ui/js/src/kimchi.main.js
            <br>
            +++ b/ui/js/src/kimchi.main.js
            <br>
            @@ -227,10 +227,7 @@ kimchi.main = function() {
            <br>
            kimchi.previousAjax = ajaxSettings;
            <br>
            $(".empty-when-logged-off").empty();
            <br>
            $(".remove-when-logged-off").remove();
            <br>
            - kimchi.window.open({
            <br>
            - url: 'login-window.html',
            <br>
            - id: 'login-window-wrapper'
            <br>
            - });
            <br>
            + document.location.href='login.html';
            <br>
            return;
            <br>
            }
            <br>
            else if((jqXHR['status'] == 0) &amp;&amp;
            ("error"==jqXHR.statusText)) {
            <br>
          </blockquote>
          <br>
          <br>
          <br>
        </blockquote>
        <br>
        <br>
      </blockquote>
      <br>
      <br>
      <br>
    </blockquote>
    <br>
    <br>
    <pre class="moz-signature" cols="72">-- 
Thanks and best regards!

Sheldon Feng(冯少合)<a class="moz-txt-link-rfc2396E" href="mailto:shaohef@linux.vnet.ibm.com">&lt;shaohef@linux.vnet.ibm.com&gt;</a>
IBM Linux Technology Center</pre>
  </body>
</html>