Created 08-22-2016 05:54 PM
I'm trying to use the Sandbox to perform queries against Zeppelin's Notebook REST API. Previously Zeppelin did not require any credentials to access notebooks. Now that they use authentication I can't seem to find a way to access it. I haven't found any documentation either.
I made the following cURL request:
curl -i -X GET http://sandbox.hortonworks.com:9995/api/notebook
This gives me a redirect with the following response:
HTTP/1.1 302 Found Date: Wed, 17 Aug 2016 08:24:39 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 8:24:39 AM UTC Set-Cookie: JSESSIONID=6b055152-eb81-4c86-8976-61e85d0541cf; Path=/; HttpOnly Location: http://sandbox.hortonworks.com:9995/api/login;JSESSIONID=6b055152-eb81-4c86-8976-61e85d0541cf Content-Length: 0 Server: Jetty(9.2.15.v20160210)
Looks like it's a redirect to /api/login
So let's try /api/login and see what happens
curl -i -X GET http://sandbox.hortonworks.com:9995/api/login
This gives the following response:
HTTP/1.1 500 Server Error Date: Wed, 17 Aug 2016 08:25:53 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 8:25:53 AM UTC Content-Type: text/html; charset=ISO-8859-1 Cache-Control: must-revalidate,no-cache,no-store Content-Length: 9546 Connection: close Server: Jetty(9.2.15.v20160210) <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Error 500 Server Error</title> </head> <body><h2>HTTP ERROR 500</h2> <p>Problem accessing /api/login. Reason: <pre> Server Error</pre></p><h3>Caused by:</h3><pre>javax.servlet.ServletException: Filtered request failed. at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:384) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.apache.zeppelin.server.CorsFilter.doFilter(CorsFilter.java:72) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) at org.eclipse.jetty.server.Server.handle(Server.java:499) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.AbstractMethodError: javax.ws.rs.core.Response.getStatusInfo()Ljavax/ws/rs/core/Response$StatusType; at javax.ws.rs.WebApplicationException.validate(WebApplicationException.java:186) at javax.ws.rs.ClientErrorException.<init>(ClientErrorException.java:88) at org.apache.cxf.jaxrs.utils.JAXRSUtils.findTargetMethod(JAXRSUtils.java:503) at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:207) at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:103) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272) at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239) at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:248) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:222) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:153) at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:167) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:211) at javax.servlet.http.HttpServlet.service(HttpServlet.java:575) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383) at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) ... 22 more </pre> <h3>Caused by:</h3><pre>java.lang.AbstractMethodError: javax.ws.rs.core.Response.getStatusInfo()Ljavax/ws/rs/core/Response$StatusType; at javax.ws.rs.WebApplicationException.validate(WebApplicationException.java:186) at javax.ws.rs.ClientErrorException.<init>(ClientErrorException.java:88) at org.apache.cxf.jaxrs.utils.JAXRSUtils.findTargetMethod(JAXRSUtils.java:503) at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:207) at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:103) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272) at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239) at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:248) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:222) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:153) at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:167) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:211) at javax.servlet.http.HttpServlet.service(HttpServlet.java:575) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383) at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.apache.zeppelin.server.CorsFilter.doFilter(CorsFilter.java:72) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) at org.eclipse.jetty.server.Server.handle(Server.java:499) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) at java.lang.Thread.run(Thread.java:745) </pre> <hr><i><small>Powered by Jetty://</small></i><hr/> </body> </html>
It's just an HTML page about the server error. I couldn't find anything in the docs on authentication.
Does anyone know how to use the REST API now that it's locked down?
Created 08-22-2016 08:49 PM
So after some more investigation and toying around with the API I've found the solution.
The first step is to authentic through the API with a POST to /api/login
curl -i --data 'userName=admin&password=password1' -X POST http://127.0.0.1:9995/api/login
This should return a response like the following:
HTTP/1.1 200 OK Date: Wed, 17 Aug 2016 10:07:22 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 10:07:22 AM UTC Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 10:07:22 GMT Set-Cookie: JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 10:07:22 GMT Content-Type: application/json Date: Wed, 17 Aug 2016 10:07:22 GMT Content-Length: 118 Server: Jetty(9.2.15.v20160210) {"status":"OK","message":"","body":{"principal":"admin","ticket":"47a1fe3a-593d-47ce-85bb-f6e7238c6dcb","roles":"[]"}}
The important thing to see here is the Set-Cookie in the response headers.
Look for the following:
Set-Cookie: JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly
Using this cookie we can make authorized request to the API by simply setting this as a cookie in the cURL request.
curl -i -b 'JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly' http://sandbox.hortonworks.com:9995/api/notebook
This request should now return a 200 OK response after adding the JSESSIONID cookie.
HTTP/1.1 200 OK Date: Wed, 17 Aug 2016 10:10:44 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 10:10:44 AM UTC Content-Type: application/json Date: Wed, 17 Aug 2016 10:10:44 GMT Content-Length: 1012 Server: Jetty(9.2.15.v20160210) {"status":"OK","message":"","body":[{"id":"2BSVACJ42","name":"/demo/note1"},{"id":"2BVBPU1VY","name":"/demo/note2"},{"id":"2APFTN3NY","name":"AON Demo"},{"id":"2ANT56EHN","name":"Australian Dataset (Hive example)"},{"id":"2ANTDG878","name":"Australian Dataset (SparkSQL example)"},{"id":"2B48PF7SN","name":"Hello World Tutorial"},{"id":"2AS5TY6AQ","name":"IoT Data Analysis (Keynote Demo)"},{"id":"2BFGYS3YT","name":"Lab 101: Intro to Spark with Python"},{"id":"2BJVW65WS","name":"Lab 102: Intro to Spark with Scala"},{"id":"2BNDT63TY","name":"Lab 201: Intro to Machine Learning with Spark"},{"id":"2B21B3AYC","name":"Phoenix demo"},{"id":"2BB5CUPUW","name":"Predicting airline delays"},{"id":"2BAVUZ7NA","name":"Sensors \u0026 Machines Predictive Analysis"},{"id":"2BBBW75VS","name":"Single view demo"},{"id":"2BEQE47HR","name":"Tutorial - Hands-on Tour of Apache Spark in 5 Minutes"},{"id":"2A94M5J1Z","name":"Zeppelin Tutorial"},{"id":"2B4TWGC8M","name":"magellan-blog"},{"id":"2B522V3X8","name":"twitter"}]}
Created 08-22-2016 08:22 PM
After doing a bit of investigating I found that I can make a successful POST to the /api/login which results in a JSON response with a ticket.
curl -i --data 'userName=admin&password=password1' -X POST http://sandbox.hortonworks.com:9995/api/login HTTP/1.1 200 OK Date: Wed, 17 Aug 2016 09:44:57 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 9:44:57 AM UTC Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 09:44:57 GMT Set-Cookie: JSESSIONID=84983c45-ceca-4db3-a366-9eab27399a68; Path=/; HttpOnly Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 09:44:57 GMT Content-Type: application/json Date: Wed, 17 Aug 2016 09:44:57 GMT Content-Length: 118 Server: Jetty(9.2.15.v20160210) {"status":"OK","message":"","body":{"principal":"admin","ticket":"47a1fe3a-593d-47ce-85bb-f6e7238c6dcb","roles":"[]"}}
Is there anything I can do with the ticket to authenticate against a notebook request?
Created 08-22-2016 08:49 PM
So after some more investigation and toying around with the API I've found the solution.
The first step is to authentic through the API with a POST to /api/login
curl -i --data 'userName=admin&password=password1' -X POST http://127.0.0.1:9995/api/login
This should return a response like the following:
HTTP/1.1 200 OK Date: Wed, 17 Aug 2016 10:07:22 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 10:07:22 AM UTC Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 10:07:22 GMT Set-Cookie: JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 16-Aug-2016 10:07:22 GMT Content-Type: application/json Date: Wed, 17 Aug 2016 10:07:22 GMT Content-Length: 118 Server: Jetty(9.2.15.v20160210) {"status":"OK","message":"","body":{"principal":"admin","ticket":"47a1fe3a-593d-47ce-85bb-f6e7238c6dcb","roles":"[]"}}
The important thing to see here is the Set-Cookie in the response headers.
Look for the following:
Set-Cookie: JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly
Using this cookie we can make authorized request to the API by simply setting this as a cookie in the cURL request.
curl -i -b 'JSESSIONID=b1f15e00-4571-4079-a699-338bf619b0c4; Path=/; HttpOnly' http://sandbox.hortonworks.com:9995/api/notebook
This request should now return a 200 OK response after adding the JSESSIONID cookie.
HTTP/1.1 200 OK Date: Wed, 17 Aug 2016 10:10:44 GMT Access-Control-Allow-Origin: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: authorization,Content-Type Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, HEAD, DELETE Date: Wednesday, August 17, 2016 10:10:44 AM UTC Content-Type: application/json Date: Wed, 17 Aug 2016 10:10:44 GMT Content-Length: 1012 Server: Jetty(9.2.15.v20160210) {"status":"OK","message":"","body":[{"id":"2BSVACJ42","name":"/demo/note1"},{"id":"2BVBPU1VY","name":"/demo/note2"},{"id":"2APFTN3NY","name":"AON Demo"},{"id":"2ANT56EHN","name":"Australian Dataset (Hive example)"},{"id":"2ANTDG878","name":"Australian Dataset (SparkSQL example)"},{"id":"2B48PF7SN","name":"Hello World Tutorial"},{"id":"2AS5TY6AQ","name":"IoT Data Analysis (Keynote Demo)"},{"id":"2BFGYS3YT","name":"Lab 101: Intro to Spark with Python"},{"id":"2BJVW65WS","name":"Lab 102: Intro to Spark with Scala"},{"id":"2BNDT63TY","name":"Lab 201: Intro to Machine Learning with Spark"},{"id":"2B21B3AYC","name":"Phoenix demo"},{"id":"2BB5CUPUW","name":"Predicting airline delays"},{"id":"2BAVUZ7NA","name":"Sensors \u0026 Machines Predictive Analysis"},{"id":"2BBBW75VS","name":"Single view demo"},{"id":"2BEQE47HR","name":"Tutorial - Hands-on Tour of Apache Spark in 5 Minutes"},{"id":"2A94M5J1Z","name":"Zeppelin Tutorial"},{"id":"2B4TWGC8M","name":"magellan-blog"},{"id":"2B522V3X8","name":"twitter"}]}
Created 03-15-2017 06:56 AM
Just using cookie like zblanco said
Created 05-09-2018 03:46 PM
I was able to succesfully post to the api/login to get the cookie and then post a notebook to the user's account using Postman. I am also able to log into the web browser successfully. However, I noticed that the notebooks when I log into Zeppelin through the browser are a different set of notebooks than when I log into zeppelin using the cookie.
Created 11-03-2018 07:50 PM
Can you please share how you did it? I´m also trying to replicate it in Postman but so far with no success....