Ravi Nori has uploaded a new change for review.

Change subject: aaa: Add support for rest api Basic auth
......................................................................

aaa: Add support for rest api Basic auth

Add support for basic authorization for
rest api

Change-Id: Ib5f6975f2d306a4dc2d81b795ab4905e5d3281a1
Bug-Url: https://bugzilla.redhat.com/1092744
Signed-off-by: Ravi Nori <rn...@redhat.com>
---
A 
backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/filters/SSORestApiLoginFilter.java
A 
backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/RestApiLoginServlet.java
M 
backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/SSOContextListener.java
M 
backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/utils/SSOUtils.java
M backend/manager/modules/enginesso/src/main/webapp/WEB-INF/web.xml
M 
backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
M backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/web.xml
7 files changed, 262 insertions(+), 25 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/86/37786/1

diff --git 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/filters/SSORestApiLoginFilter.java
 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/filters/SSORestApiLoginFilter.java
new file mode 100644
index 0000000..74fc4ad
--- /dev/null
+++ 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/filters/SSORestApiLoginFilter.java
@@ -0,0 +1,173 @@
+package org.ovirt.engine.core.aaa.filters;
+
+import org.ovirt.engine.api.extensions.ExtMap;
+import org.ovirt.engine.core.common.action.CreateUserSessionParameters;
+import org.ovirt.engine.core.common.action.VdcActionType;
+import org.ovirt.engine.core.common.action.VdcReturnValueBase;
+import org.ovirt.engine.core.common.constants.SessionConstants;
+import org.ovirt.engine.core.utils.EngineLocalConfig;
+import org.ovirt.engine.core.utils.serialization.json.JsonObjectDeserializer;
+import org.ovirt.engine.core.uutils.crypto.ticket.TicketDecoder;
+import org.ovirt.engine.core.uutils.net.HttpURLConnectionBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.net.ssl.TrustManagerFactory;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SSORestApiLoginFilter implements Filter {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private boolean loginAsAdmin = false;
+    private TicketDecoder ticketDecoder;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        try {
+            KeyStore ks = 
KeyStore.getInstance(EngineLocalConfig.getInstance().getPKITrustStoreType());
+            try (InputStream is = new 
FileInputStream(EngineLocalConfig.getInstance().getPKITrustStore())) {
+                ks.load(is, 
EngineLocalConfig.getInstance().getPKITrustStorePassword().toCharArray());
+            }
+            ticketDecoder = new TicketDecoder(ks, 
EngineLocalConfig.getInstance().getSsoStoreEku());
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to instantiate TicketDecoder", 
e);
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException,
+            ServletException {
+        HttpServletRequest req = (HttpServletRequest) request;
+        try {
+            if (!FiltersHelper.isAuthenticated(req) || 
!FiltersHelper.isSessionValid(getSessionId((HttpServletRequest) request))) {
+                authenticateWithSSO(req);
+            }
+            chain.doFilter(request, response);
+        } catch (NamingException ex) {
+            log.error("Unable to get reference to backend bean.", ex);
+            throw new RuntimeException(ex);
+        }
+    }
+
+    protected HttpURLConnection create(URL url) throws IOException, 
GeneralSecurityException {
+        Boolean verifyHost = false;
+        Boolean verifyChain = true;
+        String httpsProtocol = "TLSv1";
+        String trustManagerAlgorithm = 
TrustManagerFactory.getDefaultAlgorithm();
+        String trustStore = 
EngineLocalConfig.getInstance().getProperty("ENGINE_PKI_TRUST_STORE");
+        String trustStoreType = KeyStore.getDefaultType();
+        String trustStorePassword = 
EngineLocalConfig.getInstance().getPKITrustStorePassword();
+        Integer readTimeout = 0;
+        return new 
HttpURLConnectionBuilder(url).setHttpsProtocol(httpsProtocol)
+                .setReadTimeout(readTimeout)
+                .setTrustManagerAlgorithm(trustManagerAlgorithm)
+                .setTrustStore(trustStore)
+                .setTrustStorePassword(trustStorePassword)
+                .setTrustStoreType(trustStoreType)
+                .setURL(url)
+                .setVerifyChain(verifyChain)
+                .setVerifyHost(verifyHost).create();
+    }
+
+    protected static long copy(final InputStream input, final OutputStream 
output) throws IOException {
+        final byte[] buffer = new byte[8*1024];
+        long count = 0;
+        int n;
+        while ((n = input.read(buffer)) != -1) {
+            output.write(buffer, 0, n);
+            count += n;
+        }
+        return count;
+    }
+
+    private void authenticateWithSSO(HttpServletRequest req) throws 
ServletException {
+        String headerAuthorization = 
req.getHeader(FiltersHelper.Constants.HEADER_AUTHORIZATION);
+        HttpURLConnection connection = null;
+        try {
+            connection = create(new 
URL("https://127.0.0.1/ovirt-engine/sso/login-restapi";));
+            connection.setDoInput(true);
+            connection.setDoOutput(true);
+            connection.setRequestMethod("POST");
+            
connection.setRequestProperty(FiltersHelper.Constants.HEADER_AUTHORIZATION, 
headerAuthorization);
+            connection.setRequestProperty("Content-Type", 
"application/x-www-form-urlencoded");
+            connection.setRequestProperty("Content-Length", "" + 
Integer.toString(headerAuthorization.getBytes().length));
+            connection.setRequestProperty("Content-Language", "en-US");
+            ByteArrayOutputStream os = new ByteArrayOutputStream();
+            copy(connection.getInputStream(), os);
+            connection.connect();
+            createUserSession(req, new String(os.toByteArray(), "UTF-8"));
+        } catch (Exception e) {
+            log.error("Exception obtaining ticket from sso", e.getMessage());
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+
+    }
+
+    private void createUserSession(HttpServletRequest req, String ticket) {
+        JsonObjectDeserializer deserializer = new JsonObjectDeserializer();
+        InitialContext ctx = null;
+        try {
+            Map<String, Object> payload = 
deserializer.deserialize(ticketDecoder.decode(ticket), HashMap.class);
+            ctx = new InitialContext();
+            String username = (String) payload.get("userName");
+            VdcReturnValueBase queryRetVal = 
FiltersHelper.getBackend(ctx).runAction(VdcActionType.CreateUserSession,
+                    new CreateUserSessionParameters(
+                            (String) payload.get("profile"),
+                            (ExtMap) payload.get("authRecord"),
+                            (ExtMap) payload.get("principalRecord"),
+                            loginAsAdmin));
+            if (!queryRetVal.getSucceeded()) {
+                throw new RuntimeException(String.format("The user %s is not 
authorized to perform login", username));
+            }
+            HttpSession httpSession = req.getSession(true);
+            httpSession.setAttribute(
+                    SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY,
+                    queryRetVal.getActionReturnValue());
+        } catch (Exception ex) {
+            log.error("Exception creating user session", ex.getMessage());
+        } finally {
+            try {
+                if (ctx != null) {
+                    ctx.close();
+                }
+            } catch (NamingException ex) {
+                log.error("Unable to close context", ex);
+            }
+        }
+    }
+
+    private String getSessionId(HttpServletRequest request) {
+        String sessionId = (String) 
request.getSession(false).getAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY);
+        if (sessionId == null) {
+            sessionId = (String) 
request.getAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY);
+        }
+        return sessionId;
+    }
+    @Override
+    public void destroy() {
+    }
+
+}
diff --git 
a/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/RestApiLoginServlet.java
 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/RestApiLoginServlet.java
new file mode 100644
index 0000000..49ae67e
--- /dev/null
+++ 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/RestApiLoginServlet.java
@@ -0,0 +1,38 @@
+package org.ovirt.engine.core.sso.servlets;
+
+import org.ovirt.engine.core.sso.utils.AuthenticationUtils;
+import org.ovirt.engine.core.sso.utils.Credentials;
+import org.ovirt.engine.core.sso.utils.SSOUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class RestApiLoginServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 4414518331391974859L;
+
+    @Override
+    protected void service(HttpServletRequest request, HttpServletResponse 
response)
+            throws ServletException, IOException {
+        Credentials credentials = 
SSOUtils.getUserCredentialsFromHeader(request);
+        try {
+            if (credentials != null) {
+                AuthenticationUtils.handleCredentials(
+                        request.getSession(true),
+                        credentials.getUsername(),
+                        credentials.getPassword(),
+                        credentials.getProfile());
+                
response.getOutputStream().write(SSOUtils.issueTicket(request.getSession(true), 
request).getBytes("UTF-8"));
+                response.getOutputStream().flush();
+            } else {
+                response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+            }
+        } catch (Exception e) {
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+
+}
diff --git 
a/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/SSOContextListener.java
 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/SSOContextListener.java
index c210581..a346761 100644
--- 
a/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/SSOContextListener.java
+++ 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/servlets/SSOContextListener.java
@@ -65,7 +65,7 @@
         KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) 
ks.getEntry(
                 getStringInitParam(ctx, localConfig, SSO_STORE_ALIAS),
                 new KeyStore.PasswordProtection(passwd.toCharArray()));
-        return new TicketEncoder(entry.getCertificate(), 
entry.getPrivateKey());
+        return new TicketEncoder(entry.getCertificate(), 
entry.getPrivateKey(), 60);
     }
 
     private String getStringInitParam(ServletContext ctx, SSOLocalConfig 
localConfig, String name) {
diff --git 
a/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/utils/SSOUtils.java
 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/utils/SSOUtils.java
index 5998976..7e2d5bf 100644
--- 
a/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/utils/SSOUtils.java
+++ 
b/backend/manager/modules/enginesso/src/main/java/org/ovirt/engine/core/sso/utils/SSOUtils.java
@@ -14,6 +14,7 @@
 import javax.servlet.http.HttpSession;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.security.GeneralSecurityException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -54,42 +55,47 @@
                                         HttpServletResponse response)
             throws IOException {
         try {
-            SSOConfig config = (SSOConfig) 
session.getServletContext().getAttribute(SSO_CONFIG);
-            ExtMap principalRecord = (ExtMap) 
session.getAttribute(SSOUtils.SSO_PRINCIPAL_RECORD_ATTR_NAME);
-            String authzName = (String) 
session.getAttribute(SSOUtils.SSO_AUTHZ_ATTR_NAME);
+
             StringBuilder redirectUrl = new 
StringBuilder(SSOUtils.getParameter(request, POST_ACTION_URL));
-
-            String userId = 
config.getSsoUserGroupManager().getUserIdByExternalId(authzName, 
principalRecord.<String>get(Authz.PrincipalRecord.ID));
-            if (userId == null) {
-                userId = DEFAULT_USER_ID;
-            }
-
-            String principal = 
principalRecord.get(Authz.PrincipalRecord.PRINCIPAL);
-            Map<String, Object> payload = new HashMap<>();
-            payload.put("userId", userId);
-            payload.put("version", SSO_VERSION);
-            payload.put("userName", principal != null ? principal : 
principalRecord.<String>get(Authz.PrincipalRecord.NAME));
-            payload.put("email", 
principalRecord.<String>get(Authz.PrincipalRecord.EMAIL));
-            payload.put("groupIds", 
getGroupIds(config.getSsoUserGroupManager(), authzName, principalRecord));
-            payload.put("profile", 
session.getAttribute(SSOUtils.SSO_PROFILE_ATTR_NAME));
-            payload.put("principalRecord", principalRecord);
-            payload.put("authRecord", 
session.getAttribute(SSOUtils.SSO_AUTH_RECORD_ATTR_NAME));
-
-            ObjectMapper mapper = new 
ObjectMapper().configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
-                    
.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
-            mapper.getSerializationConfig().addMixInAnnotations(ExtMap.class, 
JsonExtMapMixIn.class);
             if (StringUtils.isNotEmpty(SSOUtils.getParameter(request, 
OPAQUE))) {
                 redirectUrl.append("&opaque=");
                 
redirectUrl.append(response.encodeURL(SSOUtils.getParameter(request, OPAQUE)));
             }
             redirectUrl.append("&ticket=");
-            redirectUrl.append(response.encodeURL(((TicketEncoder) 
request.getServletContext().getAttribute(SSO_TICKET_ENCODER)).encode(mapper.writeValueAsString(payload))));
+            redirectUrl.append(response.encodeURL(issueTicket(session, 
request)));
             response.sendRedirect(redirectUrl.toString());
         } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
     }
 
+    public static String issueTicket(HttpSession session,
+                                     HttpServletRequest request) throws 
SQLException, IOException, GeneralSecurityException {
+        SSOConfig config = (SSOConfig) 
session.getServletContext().getAttribute(SSO_CONFIG);
+        String authzName = (String) 
session.getAttribute(SSOUtils.SSO_AUTHZ_ATTR_NAME);
+        ExtMap principalRecord = (ExtMap) 
session.getAttribute(SSOUtils.SSO_PRINCIPAL_RECORD_ATTR_NAME);
+        String userId = 
config.getSsoUserGroupManager().getUserIdByExternalId(authzName, 
principalRecord.<String>get(Authz.PrincipalRecord.ID));
+        if (userId == null) {
+            userId = DEFAULT_USER_ID;
+        }
+
+        String principal = 
principalRecord.get(Authz.PrincipalRecord.PRINCIPAL);
+        Map<String, Object> payload = new HashMap<>();
+        payload.put("userId", userId);
+        payload.put("version", SSO_VERSION);
+        payload.put("userName", principal != null ? principal : 
principalRecord.<String>get(Authz.PrincipalRecord.NAME));
+        payload.put("email", 
principalRecord.<String>get(Authz.PrincipalRecord.EMAIL));
+        payload.put("groupIds", getGroupIds(config.getSsoUserGroupManager(), 
authzName, principalRecord));
+        payload.put("profile", 
session.getAttribute(SSOUtils.SSO_PROFILE_ATTR_NAME));
+        payload.put("principalRecord", principalRecord);
+        payload.put("authRecord", 
session.getAttribute(SSOUtils.SSO_AUTH_RECORD_ATTR_NAME));
+
+        ObjectMapper mapper = new 
ObjectMapper().configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+                
.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
+        mapper.getSerializationConfig().addMixInAnnotations(ExtMap.class, 
JsonExtMapMixIn.class);
+        return ((TicketEncoder) 
request.getServletContext().getAttribute(SSO_TICKET_ENCODER)).encode(mapper.writeValueAsString(payload));
+    }
+
     private static List<String> getGroupIds(SSOUserGroupManager 
userGroupManager, String authzName, ExtMap principalRecord) throws SQLException 
{
         List<String> externalGroupIds = new ArrayList<>();
         principalRecord.put(Authz.PrincipalRecord.GROUPS, 
flatGroups(principalRecord, Authz.PrincipalRecord.GROUPS, new 
ArrayList<ExtMap>()));
diff --git a/backend/manager/modules/enginesso/src/main/webapp/WEB-INF/web.xml 
b/backend/manager/modules/enginesso/src/main/webapp/WEB-INF/web.xml
index d48ab46..89dc62d 100644
--- a/backend/manager/modules/enginesso/src/main/webapp/WEB-INF/web.xml
+++ b/backend/manager/modules/enginesso/src/main/webapp/WEB-INF/web.xml
@@ -189,6 +189,16 @@
     </servlet-mapping>
 
     <servlet>
+        <servlet-name>RestApiLoginServlet</servlet-name>
+        
<servlet-class>org.ovirt.engine.core.sso.servlets.RestApiLoginServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>RestApiLoginServlet</servlet-name>
+        <url-pattern>/login-restapi</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
         <servlet-name>LogoutServlet</servlet-name>
         
<servlet-class>org.ovirt.engine.core.sso.servlets.LogoutServlet</servlet-class>
     </servlet>
diff --git 
a/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
 
b/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 3b9302f..7a07986 100644
--- 
a/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ 
b/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -35,6 +35,7 @@
       <module name="org.ovirt.engine.api.restapi-jaxrs" annotations="true" 
services="import"/>
       <module name="org.ovirt.engine.api.restapi-types" annotations="true" 
services="import"/>
       <module name="org.ovirt.engine.core.aaa"/>
+      <module name="org.ovirt.engine.api.ovirt-engine-extensions-api"/>
 
     </dependencies>
   </deployment>
diff --git 
a/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/web.xml 
b/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/web.xml
index ff1470f..11030b1 100644
--- a/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/web.xml
+++ b/backend/manager/modules/restapi/webapp/src/main/webapp/WEB-INF/web.xml
@@ -70,6 +70,15 @@
     </filter-mapping>
 
     <filter>
+        <filter-name>SSORestApiLoginFilter</filter-name>
+        
<filter-class>org.ovirt.engine.core.aaa.filters.SSORestApiLoginFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>SSORestApiLoginFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <filter>
         <filter-name>BasicAuthenticationFilter</filter-name>
         
<filter-class>org.ovirt.engine.core.aaa.filters.BasicAuthenticationFilter</filter-class>
         <init-param>


-- 
To view, visit http://gerrit.ovirt.org/37786
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib5f6975f2d306a4dc2d81b795ab4905e5d3281a1
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Ravi Nori <rn...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to