• OKMAuth login with token not working

  • We tried to make OpenKM as intuitive as possible, but an advice is always welcome.
We tried to make OpenKM as intuitive as possible, but an advice is always welcome.
Forum rules: Please, before asking something see the documentation wiki or use the search feature of the forum. And remember we don't have a crystal ball or mental readers, so if you post about an issue tell us which OpenKM are you using and also the browser and operating system version. For more info read How to Report Bugs Effectively.
 #41441  by Catscratch
 
Hey guys,

I noticed a bug in OpenKM. When trying to login using OKMAuth.getInstance().login(username, password) interface for the first time I got a server error indicating, that the user doesn't have the right to access okm:trash. The problem here is that the user did not get the default role defined in spring context (ROLE_USER).

When I use OKMAuth.getInstance().login() - so without username and password - everything is working fine. There you get the roles from spring context which also contains the default role. But I really need the login(String, String) to get a token and do everything following with token instead of username and password.

The login(String, String) methods seems to ignore the spring context. It only gets the roles from PrincipalAdapter.

It seems like a bug. Can you please have a look whats going wrong here?

I checked the roles after login(String, String) call by using OKMAuth.getInstance().getRolesByUser(username) which do not contain the default role (ROLE_USER).

Thanks!
 #41451  by jllort
 
Can you give us some code for checking what are you doing in our dev environments.
Also I would like to understanding from where you are executing the code, Workflow, scripting, crontab task ?
 #41454  by Catscratch
 
Ok. Steps to reproduce:

1. Configure LDAP in OpenKM.xml and inside OpenKM Configuration
2. Set defaultRole to "ROLE_USER" in OpenKM.xml
Code: Select all
<beans:property name="defaultRole" value="ROLE_USER" />
So, in our configuration, no LDAP user explicitely owns ROLE_USER. But every user gets ROLE_USER with Spring Context when logging in (by defaultRole).
3. Create a completely new user in LDAP (I used "newuser" with "newpass")
4. Use REST and try to auth (do not login via website with this user)
Code: Select all
http://localhost:8080/archiv/services/rest/auth/login
Set Basic Auth to "newuser" and "newpass".
5. See exception returned.
Code: Select all
RepositoryException: PathNotFoundException: c2e094a5-721c-450d-947f-6eff64f2feeb : /okm:trash
This exceptions occurs because the user does not own the ROLE_USER and therefore cannot create his trash node. If the user logs in using the website the Spring context gives him the ROLE_USER (defined by defaultRole). So it is possible to login for this user and create the trash.

So, when using rest endpoint, the user don't get the ROLE_USER because there is no updated Spring context. I would assume, that the user also gets the defaultRole defined in OpenKM.xml. Or at least, get the defaultRole defined in OpenKM configurations tab. If not, there is no benefit of defining defaultRole, because you have to set ROLE_USER explicitly for every user in LDAP.

Thanks for having a look.
 #41461  by jllort
 
OK I understood the problem and the cause of it. The problem is that the user who's executing across ws has never logged to OpenKM and has some missing folders ( when users login into OpenKM application automatically creates missing folders, but it not happens from ws side ). In AuthService we have added new method named login , this method really does not do the classic login, really emulates the login section what build missing folders.

Before using any user you should execute the login method from Auth webservice calling another method before you will the the missing trash node.
 #41483  by Catscratch
 
Ok, now I got time to test. I updated to the latest sources from sourceforge.

Here are the steps to reproduce.

1. log into okm using okmAdmin and create a new user (I called him "newuser" with password "newuser") -> do not log into openkm using web ui!
2. call rest endpoint and see the exception
Code: Select all
curl -X GET -H "Content-Type: application/xml" -H "Authorization: Basic bmV3dXNlcjpuZXd1c2Vy" -H "Cache-Control: no-cache" -H "Postman-Token: caa90f9d-dcb1-a84c-26f2-8effd2101f03" "http://localhost:8080/archiv/services/rest/auth/login"
3. Answer from openkm:
Code: Select all
RepositoryException: PathNotFoundException: c2e094a5-721c-450d-947f-6eff64f2feeb : /okm:trash
4. Exception in openkm:
Code: Select all
ERROR com.openkm.module.db.DbAuthModule - c2e094a5-721c-450d-947f-6eff64f2feeb : /okm:trash 
com.openkm.core.PathNotFoundException: c2e094a5-721c-450d-947f-6eff64f2feeb : /okm:trash
	at com.openkm.module.db.stuff.SecurityHelper.checkRead(SecurityHelper.java:98)
	at com.openkm.dao.NodeFolderDAO.create(NodeFolderDAO.java:102)
	at com.openkm.module.db.DbAuthModule.createBase(DbAuthModule.java:674)
	at com.openkm.module.db.DbAuthModule.loadUserData(DbAuthModule.java:633)
	at com.openkm.module.db.DbAuthModule.login(DbAuthModule.java:81)
	at com.openkm.rest.endpoint.AuthService.login(AuthService.java:55)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:188)
	at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:104)
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:204)
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:101)
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58)
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:94)
	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:241)
	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:171)
	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:624)
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
 #41493  by jllort
 
The error is caused because user has never log into the application from UI and the /okm:trash node has not been created. The main nodes are created the first time user is logged into application. For it we have created a method in rest for simulating this login
https://sourceforge.net/p/openkm/code/H ... rvice.java

I see you are calling the login from rest but I'm not seeing the username and password
Code: Select all
curl -u newuser:newuser -H "Accept: application/json" \
   http://localhost:8080/OpenKM/services/rest/rest/auth/login
Also I seen you have changed application context OpenKM to archiv ( not a great idea, because for UI we are using this context value internally, I'm talking about static values ).
 #41494  by Catscratch
 
I don't really understand. I know the problem.

Now I'm looking forward to solve it. As you see in my curl request I already call the AuthService /login method. I also deliver username and password (parameter -u). It's put into BasicAuth header "Authorization: Basic bmV3dXNlcjpuZXd1c2Vy".

And then the exception above raises (okm:trash). When I have a look into the code you linked, there is no "simulation" in auth method. Can you tell me how I may use the rest api to "simulate" a UI login? Do I have to call updateUser or something like this?
 #41512  by jllort
 
I have checked latest openkm community with this codes and is going right:
Code: Select all
public class Test {
	public static void main(String[] args) {
		String host = "http://localhost:8180/OpenKM";
		String user = "test2";
		String password = "test2";
		
		OKMWebservices ws = OKMWebservicesFactory.newInstance(host, user, password);
		try {
            ws.login(); // simulates user first login from UI creating missing folders like /okm:trash
            for (Folder folder : ws.getFolderChildren("/okm:root")) {
                System.out.println(folder);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
}
Actually the sdk for Java is still not released, but I can release a 1.2-DEV if it can helps you in some way.
 #41520  by Catscratch
 
Hm, it seems that the OKMWebservices.login() method is doing the magic, right? Because, when I directly call the REST endpoint (without the SDK) it will fail without success. So my question is, what do you do inside the OKMWebservices.login() method? Can I see sources anywhere?

Thanks!
 #41526  by jllort
 
This is the code, really is not doing anything strange here:
Code: Select all
public void login() throws UnknowException, WebserviceException {
        Client client = getClient();
        try {
            String uri = UriHelper.getUri(host, UriHelper.AUTH_LOGIN);
            WebResource resource = client.resource(uri);
            ClientResponse cResponse = resource.accept(MediaType.APPLICATION_XML).type(MediaType.APPLICATION_FORM_URLENCODED)
                    .get(ClientResponse.class);
            
            if (cResponse.getStatus() != Status.NO_CONTENT.getStatusCode()) {
                String error = cResponse.getEntity(String.class);
                if (cResponse.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
                    if (error.indexOf(":") > 0) {
                        String msg = error.substring(error.indexOf(":") + 1);
                        throw new UnknowException(msg);
                    } else {
                        throw new UnknowException("HTTP error code " + cResponse.getStatus() + ": " + error);
                    }
                } else {
                    throw new UnknowException("HTTP error code " + cResponse.getStatus() + ": " + error);
                }
            }
        } catch (ClientHandlerException e) {
            throw new WebserviceException(e);
        } finally {
            if (client != null) {
                client.destroy();
            }
        }
    }
getClient(); // returns authenticated client ( with jersey )
UriHelper.getUri(host, UriHelper.AUTH_LOGIN); // return the url, nothing else
The call is make with xml, but with json is exactly the same.

I suggest you debug from server side, to see if your curl call is really going right.
 #41560  by Catscratch
 
Ok. I found it. We created a new REST Endpoint inside OpenKM with Token authentication and on top of Swagger (and Swagger UI) which is really nice and gives a very good rest documentation.

Anyway. By this, we disabled basic auth for this rest endpoint and used header params for authentication (using https). Because its annoying to devliver username and password for every rest call. Anyway. The new rest endpoint is working great except in the case above.

Now I found out what the problem was. By not using basic auth spring doesn't know the user context. So when calling OKMAuth.login(username, password) method the underlying function for creating the trash tries to create it with an anonymous user (because the spring context only holds an anonymous user at this moment).

So we switched back to basic auth, but only for login rest endpoint. Now everything is working. The spring context got the user information back and the trash could be created.

So our new rest endpoint looks like this, that we use basic auth for calling /login which returns a token and all other rest methods use this token and work without basic auth.

Thanks for your help!
 #41562  by jllort
 
If the problem is sending authentication in plain text why you are not using https connection with actual rest ? Is not necessary create a new rest service for getting authentication with SSL or I'm missing something ?

About Us

OpenKM is part of the management software. A management software is a program that facilitates the accomplishment of administrative tasks. OpenKM is a document management system that allows you to manage business content and workflow in a more efficient way. Document managers guarantee data protection by establishing information security for business content.