package com.orientechnologies.orient.server.network.protocol.http.command.post; import java.io.IOException; import java.util.Map; import com.orientechnologies.common.concur.lock.OLockException; import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.config.OGlobalConfiguration; import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.exception.ODatabaseException; import com.orientechnologies.orient.core.exception.OSecurityAccessException; import com.orientechnologies.orient.core.metadata.security.OSecurityUser; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.server.OTokenHandler; import com.orientechnologies.orient.server.network.protocol.http.OHttpRequest; import com.orientechnologies.orient.server.network.protocol.http.OHttpResponse; import com.orientechnologies.orient.server.network.protocol.http.OHttpUtils; import com.orientechnologies.orient.server.network.protocol.http.command.OServerCommandAbstract; /** * Created by emrul on 14/09/14. * * @author Emrul Islam <emrul@emrul.com> Copyright 2014 Emrul Islam */ public class OServerCommandPostAuthToken extends OServerCommandAbstract { private static final String[] NAMES = { "POST|token/*" }; private static final String RESPONSE_FORMAT = "indent:-1,attribSameRow"; private volatile OTokenHandler tokenHandler; @Override public String[] getNames() { return NAMES; } private void init() { if (tokenHandler == null && OGlobalConfiguration.NETWORK_HTTP_USE_TOKEN.getValueAsBoolean()) { tokenHandler = server.getTokenHandler(); } } @Override public boolean execute(OHttpRequest iRequest, OHttpResponse iResponse) throws Exception { init(); String[] urlParts = checkSyntax(iRequest.url, 2, "Syntax error: token/<database>"); iRequest.databaseName = urlParts[1]; iRequest.data.commandInfo = "Generate authentication token"; // Parameter names consistent with 4.3.2 (Access Token Request) of RFC 6749 Map<String, String> content = iRequest.getUrlEncodedContent(); if(content == null){ ODocument result = new ODocument().field("error", "missing_auth_data"); sendError(iRequest, iResponse, result); return false; } String signedToken = "";// signedJWT.serialize(); String grantType = content.get("grant_type").toLowerCase(); String username = content.get("username"); String password = content.get("password"); String authenticatedRid; ODocument result; if (grantType.equals("password")) { authenticatedRid = authenticate(username, password, iRequest.databaseName); if (authenticatedRid == null) { sendAuthorizationRequest(iRequest, iResponse, iRequest.databaseName); } else if (tokenHandler != null) { // Generate and return a JWT access token ODatabaseDocument db = null; OSecurityUser user = null; try { db = (ODatabaseDocument) server.openDatabase(iRequest.databaseName, username, password); user = db.getUser(); if (user != null) { byte[] tokenBytes = tokenHandler.getSignedWebToken(db, user); signedToken = new String(tokenBytes); } else { // Server user (not supported yet!) } } catch (OSecurityAccessException e) { // WRONG USER/PASSWD } catch (OLockException e) { OLogManager.instance().error(this, "Cannot access to the database '" + iRequest.databaseName + "'", ODatabaseException.class, e); } finally { if (db != null) { db.close(); } } // 4.1.4 (Access Token Response) of RFC 6749 result = new ODocument().field("access_token", signedToken).field("expires_in", 3600); iResponse.writeRecord(result, RESPONSE_FORMAT, null); } else { result = new ODocument().field("error", "unsupported_grant_type"); sendError(iRequest, iResponse, result); } } else { result = new ODocument().field("error", "unsupported_grant_type"); sendError(iRequest, iResponse, result); } return false; } // Return user rid if authentication successful. // If user is server user (doesn't have a rid) then '<server user>' is returned. // null is returned in all other cases and means authentication was unsuccessful. protected String authenticate(final String username, final String password, final String iDatabaseName) throws IOException { ODatabaseDocument db = null; String userRid = null; try { db = (ODatabaseDocument) server.openDatabase(iDatabaseName, username, password); userRid = (db.getUser() == null ? "<server user>" : db.getUser().getDocument().getIdentity().toString()); } catch (OSecurityAccessException e) { // WRONG USER/PASSWD } catch (OLockException e) { OLogManager.instance().error(this, "Cannot access to the database '" + iDatabaseName + "'", ODatabaseException.class, e); } finally { if (db != null) { db.close(); } } return userRid; } protected void sendError(final OHttpRequest iRequest, final OHttpResponse iResponse, final ODocument error) throws IOException { iResponse.send(OHttpUtils.STATUS_BADREQ_CODE, OHttpUtils.STATUS_BADREQ_DESCRIPTION, OHttpUtils.CONTENT_JSON, error.toJSON(), null); } protected void sendAuthorizationRequest(final OHttpRequest iRequest, final OHttpResponse iResponse, final String iDatabaseName) throws IOException { // Defaults to "WWW-Authenticate: Basic". String header = server.getSecurity().getAuthenticationHeader(iDatabaseName); if (isJsonResponse(iResponse)) { sendJsonError(iResponse, OHttpUtils.STATUS_BADREQ_CODE, OHttpUtils.STATUS_BADREQ_DESCRIPTION, OHttpUtils.CONTENT_TEXT_PLAIN, "401 Unauthorized.", header); } else { iResponse.send(OHttpUtils.STATUS_AUTH_CODE, OHttpUtils.STATUS_AUTH_DESCRIPTION, OHttpUtils.CONTENT_TEXT_PLAIN, "401 Unauthorized.", header); } } }