Our Community is getting an upgrade! To get everything ready for the relaunch, we’ll be placing the site in read-only mode starting September 21st.
We really appreciate your understanding while we get things set up behind the scenes. Catch up on all the exciting details about the move here.
Need help or have questions? Drop us a line at [email protected]
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....