001/*
002 * Copyright (c) 2017 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2017-08-23 22:42:39 -0700 (Wed, 23 Aug 2017) $' 
007 * '$Revision: 1375 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.webview.server.handler;
030
031import java.net.HttpURLConnection;
032import java.util.Set;
033
034import org.kepler.webview.server.WebViewConfiguration;
035import org.kepler.webview.server.WebViewServer;
036import org.kepler.webview.server.auth.AuthUtilities;
037
038import io.vertx.core.file.FileSystem;
039import io.vertx.core.json.JsonArray;
040import io.vertx.core.json.JsonObject;
041import io.vertx.ext.web.RoutingContext;
042
043/** Handler for logins.
044 * 
045 * @author Daniel Crawl
046 * @version $Id: LoginHandler.java 1375 2017-08-24 05:42:39Z crawl $
047 */
048public class LoginHandler extends BaseHandler {
049
050    public LoginHandler(WebViewServer server) {
051        super(server);
052        _metadataFileName = WebViewConfiguration.getHttpServerMetadataFileName();
053        _fileSystem = _server.getVertx().fileSystem();
054    }
055
056    @Override
057    public void handle(RoutingContext context) {
058
059        final long timestamp = System.currentTimeMillis();
060        
061        /*
062        System.out.println("logged in " + 
063            context.user().principal().getString("username") + " " +
064            context.session().id());
065         */
066        
067        // get the last modified time of the metadata file.
068        _fileSystem.props(_metadataFileName, propsResult -> {
069            if(propsResult.succeeded()) {
070                // see if file was modified since we last read it
071                if(propsResult.result().lastModifiedTime() > _metadataLastModifiedTime || _metadataJson == null) {
072                    _metadataLastModifiedTime = propsResult.result().lastModifiedTime();
073                    
074                    // read metadata file
075                    _fileSystem.readFile(_metadataFileName, readResult -> {
076                        if(readResult.succeeded()) {
077                            // update the cached json
078                            try {
079                                _metadataJson = readResult.result().toJsonArray();
080                            } catch(Throwable t) {
081                                context.response()
082                                    .putHeader("Content-Type", "text/plain")
083                                    .setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
084                                    .setStatusMessage("Could not access metadata.")
085                                    .end();
086                                System.err.println("Error reading metadata file " +
087                                    _metadataFileName + ": " + t.getMessage());
088                                _server.log(context.request(), context.user(), HttpURLConnection.HTTP_INTERNAL_ERROR, timestamp);
089                                return;
090                            }
091                            // send metadata json in response
092                            _sendMetadata(context, timestamp);
093                        } else {
094                            context.response()
095                                .putHeader("Content-Type", "text/plain")
096                                .setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
097                                .setStatusMessage("Could not access metadata.")
098                                .end();
099                            System.err.println("Could not read metadata " +
100                                    _metadataFileName + ": " + readResult.cause().getMessage());
101                            _server.log(context.request(), context.user(), HttpURLConnection.HTTP_INTERNAL_ERROR, timestamp);
102                        }
103                    });
104                } else {
105                    // send cached metadata json in response 
106                    _sendMetadata(context, timestamp);
107                }                
108            } else {
109                context.response()
110                    .putHeader("Content-Type", "text/plain")
111                    .setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
112                    .setStatusMessage("Could not access metadata.")
113                    .end();
114                System.err.println("Could not get properties for metadata " +
115                    _metadataFileName + ": " + propsResult.cause().getMessage());
116                _server.log(context.request(), context.user(), HttpURLConnection.HTTP_INTERNAL_ERROR, timestamp);
117            }                
118        });
119    }
120
121    /** Send metadata JSON in response.
122     * @param context The vertx routing context.
123     * @param timestamp The timestamp of the request.
124     */
125    private void _sendMetadata(RoutingContext context, long timestamp) {
126        
127        // construct the response json
128        
129        JsonObject principal = context.user().principal();
130        Set<String> userGroups = AuthUtilities.getGroups(context.user());        
131        
132        JsonObject returnJson = new JsonObject();
133        
134        // add the username
135        returnJson.put("username", principal.getString("username"));
136        returnJson.put("fullname", principal.getString("fullname"));
137        
138        // add the groups
139        JsonArray groupsArray = new JsonArray();
140        for(String groupName : userGroups) {
141            groupsArray.add(groupName);
142        }
143        returnJson.put("groups", groupsArray);
144
145        // add metadata
146
147        if(userGroups.contains("admin")) {
148            returnJson.put("metadata", _metadataJson.copy());
149        } else { 
150            JsonArray returnMetadataJson = new JsonArray();
151            for(int i = 0; i < _metadataJson.size(); i++) {
152                JsonObject m = _metadataJson.getJsonObject(i);
153                boolean inGroup = false;
154                if(!m.containsKey("groups")) {
155                    inGroup = true;
156                } else {
157                    JsonArray groupsList = m.getJsonArray("groups");
158                    for(int j = 0; j < groupsList.size(); j++) {
159                        if(userGroups.contains(groupsList.getString(j))) {
160                            inGroup = true;
161                            break;
162                        }
163                    }
164                }
165                
166                if(inGroup) {
167                    returnMetadataJson.add(m.copy());
168                }
169            };
170            returnJson.put("metadata", returnMetadataJson);
171        }
172               
173        //System.out.println(returnJson.encodePrettily());
174        
175        context.response().putHeader("Content-Type", "application/json")
176            .end(returnJson.encode());
177        _server.log(context.request(), context.user(), HttpURLConnection.HTTP_OK, timestamp);
178    }
179    
180    /** Vertx file system. */
181    private FileSystem _fileSystem;
182    
183    /** Metadata file name. */
184    private String _metadataFileName;
185    
186    /** Last modified time of metadata file. */
187    private long _metadataLastModifiedTime = -1;
188    
189    /** Metadata JSON cached from reading metadata file. */
190    private JsonArray _metadataJson;
191}