14a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#!/usr/bin/python2.5 272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen# Copyright (c) 2011 The Chromium Authors. All rights reserved. 34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch# Use of this source code is governed by a BSD-style license that can be 44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch# found in the LICENSE file. 54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 64a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch"""A bare-bones test server for testing cloud policy support. 74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochThis implements a simple cloud policy test server that can be used to test 94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochchrome's device management service client. The policy information is read from 1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenthe file named device_management in the server's data directory. It contains 1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenenforced and recommended policies for the device and user scope, and a list 1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenof managed users. 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenThe format of the file is JSON. The root dictionary contains a list under the 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenkey "managed_users". It contains auth tokens for which the server will claim 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenthat the user is managed. The token string "*" indicates that all users are 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenclaimed to be managed. Other keys in the root dictionary identify request 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenscopes. Each request scope is described by a dictionary that holds two 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensub-dictionaries: "mandatory" and "recommended". Both these hold the policy 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsendefinitions as key/value stores, their format is identical to what the Linux 2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimplementation reads from /etc. 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExample: 244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch{ 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "chromeos/device": { 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "mandatory": { 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "HomepageLocation" : "http://www.chromium.org" 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen }, 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "recommended": { 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "JavascriptEnabled": false, 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen }, 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen }, 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "managed_users": [ 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "secret123456" 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ] 374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch""" 414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport cgi 434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport logging 4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimport os 454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport random 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport re 474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport sys 4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimport time 4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimport tlslite 5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimport tlslite.api 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport tlslite.utils 524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch# The name and availability of the json module varies in python versions. 544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochtry: 554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch import simplejson as json 564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochexcept ImportError: 574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch try: 584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch import json 594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch except ImportError: 604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch json = None 614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport asn1der 634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochimport device_management_backend_pb2 as dm 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenimport cloud_policy_pb2 as cp 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenimport chrome_device_policy_pb2 as dp 6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen# ASN.1 object identifier for PKCS#1/RSA. 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenPKCS1_RSA_OID = '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01' 694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass RequestHandler(object): 714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Decodes and handles device management requests from clients. 724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch The handler implements all the request parsing and protobuf message decoding 744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch and encoding. It calls back into the server to lookup, register, and 754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch unregister clients. 764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def __init__(self, server, path, headers, request): 794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Initialize the handler. 804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch server: The TestServer object to use for (un)registering clients. 834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch path: A string containing the request path and query parameters. 844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch headers: A rfc822.Message-like object containing HTTP headers. 854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch request: The request data received from the client as a string. 864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._server = server 884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._path = path 894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._headers = headers 904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._request = request 914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._params = None 924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def GetUniqueParam(self, name): 944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Extracts a unique query parameter from the request. 954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch name: Names the parameter to fetch. 984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch The parameter value or None if the parameter doesn't exist or is not 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch unique. 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if not self._params: 103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen self._params = cgi.parse_qs(self._path[self._path.find('?') + 1:]) 1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch param_list = self._params.get(name, []) 1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if len(param_list) == 1: 1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return param_list[0] 1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return None; 1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def HandleRequest(self): 1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Handles a request. 1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Parses the data supplied at construction time and returns a pair indicating 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch http status code and response data to be sent back to the client. 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch A tuple of HTTP status code and response data to send to the client. 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch rmsg = dm.DeviceManagementRequest() 1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch rmsg.ParseFromString(self._request) 1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen logging.debug('auth -> ' + self._headers.getheader('Authorization', '')) 123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen logging.debug('deviceid -> ' + self.GetUniqueParam('deviceid')) 1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.DumpMessage('Request', rmsg) 1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch request_type = self.GetUniqueParam('request') 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen # Check server side requirements, as defined in 128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen # device_management_backend.proto. 129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (self.GetUniqueParam('devicetype') != '2' or 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen self.GetUniqueParam('apptype') != 'Chrome' or 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (request_type != 'ping' and 132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen len(self.GetUniqueParam('deviceid')) >= 64) or 133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen len(self.GetUniqueParam('agent')) >= 64): 134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return (400, 'Invalid request parameter') 1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if request_type == 'register': 1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return self.ProcessRegister(rmsg.register_request) 1374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch elif request_type == 'unregister': 1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return self.ProcessUnregister(rmsg.unregister_request) 139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elif request_type == 'policy' or request_type == 'ping': 140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self.ProcessPolicy(rmsg.policy_request, request_type) 1414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch else: 1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (400, 'Invalid request parameter') 1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen def CheckGoogleLogin(self): 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen """Extracts the GoogleLogin auth token from the HTTP request, and 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen returns it. Returns None if the token is not present. 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen """ 14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen match = re.match('GoogleLogin auth=(\\w+)', 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen self._headers.getheader('Authorization', '')) 15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if not match: 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return None 15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return match.group(1) 15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def ProcessRegister(self, msg): 1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Handles a register request. 1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Checks the query for authorization and device identifier, registers the 1584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch device with the server and constructs a response. 1594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 1614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg: The DeviceRegisterRequest message received from the client. 1624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 1644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch A tuple of HTTP status code and response data to send to the client. 1654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 1664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Check the auth token and device ID. 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if not self.CheckGoogleLogin(): 1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (403, 'No authorization') 1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch device_id = self.GetUniqueParam('deviceid') 1714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if not device_id: 1724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (400, 'Missing device identifier') 1734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 174dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen token_info = self._server.RegisterDevice(device_id, 175dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen msg.machine_id, 176dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen msg.type) 1774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Send back the reply. 1794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response = dm.DeviceManagementResponse() 180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen response.register_response.device_management_token = ( 181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen token_info['device_token']) 182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen response.register_response.machine_name = token_info['machine_name'] 1834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.DumpMessage('Response', response) 1854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (200, response.SerializeToString()) 1874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def ProcessUnregister(self, msg): 1894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Handles a register request. 1904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Checks for authorization, unregisters the device and constructs the 1924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response. 1934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 1954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg: The DeviceUnregisterRequest message received from the client. 1964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch A tuple of HTTP status code and response data to send to the client. 1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 2004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Check the management token. 2014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch token, response = self.CheckToken(); 2024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if not token: 2034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return response 2044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Unregister the device. 2064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._server.UnregisterDevice(token); 2074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Prepare and send the response. 2094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response = dm.DeviceManagementResponse() 2104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response.unregister_response.CopyFrom(dm.DeviceUnregisterResponse()) 2114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.DumpMessage('Response', response) 2134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (200, response.SerializeToString()) 2154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def ProcessInitialPolicy(self, msg): 217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """Handles a 'preregister policy' request. 21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Queries the list of managed users and responds the client if their user 22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is managed or not. 22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Args: 223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen msg: The PolicyFetchRequest message received from the client. 22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Returns: 22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen A tuple of HTTP status code and response data to send to the client. 22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen """ 228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen # Check the GAIA token. 22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen auth = self.CheckGoogleLogin() 23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if not auth: 23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return (403, 'No authorization') 23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen chrome_initial_settings = dm.ChromeInitialSettingsProto() 23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if ('*' in self._server.policy['managed_users'] or 23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen auth in self._server.policy['managed_users']): 236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen chrome_initial_settings.enrollment_provision = ( 237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dm.ChromeInitialSettingsProto.MANAGED); 23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen else: 239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen chrome_initial_settings.enrollment_provision = ( 240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dm.ChromeInitialSettingsProto.UNMANAGED); 241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data = dm.PolicyData() 243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.policy_type = msg.policy_type 244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.policy_value = chrome_initial_settings.SerializeToString() 24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # Prepare and send the response. 24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen response = dm.DeviceManagementResponse() 248dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen fetch_response = response.policy_response.response.add() 249dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen fetch_response.policy_data = ( 250dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.SerializeToString()) 25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen self.DumpMessage('Response', response) 25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return (200, response.SerializeToString()) 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def ProcessDevicePolicy(self, msg): 257dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """Handles a policy request that uses the deprecated protcol. 258dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen TODO(gfeher): Remove this when we certainly don't need it. 2594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Checks for authorization, encodes the policy into protobuf representation 26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen and constructs the response. 2624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 2644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg: The DevicePolicyRequest message received from the client. 2654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 2674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch A tuple of HTTP status code and response data to send to the client. 2684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 2704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Check the management token. 2714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch token, response = self.CheckToken() 2724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if not token: 2734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return response 2744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Stuff the policy dictionary into a response message and send it back. 2764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response = dm.DeviceManagementResponse() 2774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response.policy_response.CopyFrom(dm.DevicePolicyResponse()) 2784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # Respond only if the client requested policy for the cros/device scope, 2804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch # since that's where chrome policy is supposed to live in. 281dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if msg.policy_scope == 'chromeos/device': 282dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy = self._server.policy['google/chromeos/user']['mandatory'] 2834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch setting = response.policy_response.setting.add() 2844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch setting.policy_key = 'chrome-policy' 2854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch policy_value = dm.GenericSetting() 28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (key, value) in policy.iteritems(): 2874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry = policy_value.named_value.add() 2884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry.name = key 2894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value = dm.GenericValue() 2904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if isinstance(value, bool): 2914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.value_type = dm.GenericValue.VALUE_TYPE_BOOL 2924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.bool_value = value 2934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch elif isinstance(value, int): 2944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.value_type = dm.GenericValue.VALUE_TYPE_INT64 2954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.int64_value = value 2964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch elif isinstance(value, str) or isinstance(value, unicode): 2974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING 2984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.string_value = value 2994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch elif isinstance(value, list): 3004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING_ARRAY 3014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch for list_entry in value: 3024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry_value.string_array.append(str(list_entry)) 3034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch entry.value.CopyFrom(entry_value) 3044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch setting.policy_value.CopyFrom(policy_value) 3054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.DumpMessage('Response', response) 3074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (200, response.SerializeToString()) 3094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def ProcessPolicy(self, msg, request_type): 311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """Handles a policy request. 312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Checks for authorization, encodes the policy into protobuf representation 314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen and constructs the response. 315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 316dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Args: 317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen msg: The DevicePolicyRequest message received from the client. 318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 319dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Returns: 320dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen A tuple of HTTP status code and response data to send to the client. 321dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """ 322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 323dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if msg.request: 324dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for request in msg.request: 325dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if request.policy_type == 'google/chromeos/unregistered_user': 326dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if request_type != 'ping': 327dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return (400, 'Invalid request type') 328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self.ProcessInitialPolicy(request) 329dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elif (request.policy_type in 330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ('google/chromeos/user', 'google/chromeos/device')): 331dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if request_type != 'policy': 332dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return (400, 'Invalid request type') 333dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self.ProcessCloudPolicy(request) 334dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen else: 335dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return (400, 'Invalid policy_type') 336dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen else: 337dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self.ProcessDevicePolicy(msg) 338dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen def SetProtobufMessageField(self, group_message, field, field_value): 34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen '''Sets a field in a protobuf message. 34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 34272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Args: 34372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen group_message: The protobuf message. 34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen field: The field of the message to set, it shuold be a member of 34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen group_message.DESCRIPTOR.fields. 34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen field_value: The value to set. 34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ''' 348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if field.label == field.LABEL_REPEATED: 349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen assert type(field_value) == list 350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entries = group_message.__getattribute__(field.name) 351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for list_item in field_value: 352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entries.append(list_item) 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen elif field.type == field.TYPE_BOOL: 355dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen assert type(field_value) == bool 356dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elif field.type == field.TYPE_STRING: 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen assert type(field_value) == str or type(field_value) == unicode 358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elif field.type == field.TYPE_INT64: 359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen assert type(field_value) == int 360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elif (field.type == field.TYPE_MESSAGE and 361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen field.message_type.name == 'StringList'): 36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen assert type(field_value) == list 363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entries = group_message.__getattribute__(field.name).entries 36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for list_item in field_value: 365dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entries.append(list_item) 366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return 36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen else: 368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen raise Exception('Unknown field type %s' % field.type) 369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen group_message.__setattr__(field.name, field_value) 37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen def GatherDevicePolicySettings(self, settings, policies): 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen '''Copies all the policies from a dictionary into a protobuf of type 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CloudDeviceSettingsProto. 374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Args: 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen settings: The destination ChromeDeviceSettingsProto protobuf. 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policies: The source dictionary containing policies in JSON format. 378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ''' 379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for group in settings.DESCRIPTOR.fields: 380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Create protobuf message for group. 381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen group_message = eval('dp.' + group.message_type.name + '()') 382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Indicates if at least one field was set in |group_message|. 383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen got_fields = False 384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Iterate over fields of the message and feed them from the 385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # policy config file. 386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for field in group_message.DESCRIPTOR.fields: 387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen field_value = None 388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if field.name in policies: 389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen got_fields = True 390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen field_value = policies[field.name] 391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.SetProtobufMessageField(group_message, field, field_value) 392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if got_fields: 393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen settings.__getattribute__(group.name).CopyFrom(group_message) 394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen def GatherUserPolicySettings(self, settings, policies): 39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen '''Copies all the policies from a dictionary into a protobuf of type 39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CloudPolicySettings. 39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Args: 40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen settings: The destination: a CloudPolicySettings protobuf. 40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen policies: The source: a dictionary containing policies under keys 40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 'recommended' and 'mandatory'. 40372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ''' 40472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for group in settings.DESCRIPTOR.fields: 40572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # Create protobuf message for group. 40672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen group_message = eval('cp.' + group.message_type.name + '()') 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # We assume that this policy group will be recommended, and only switch 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # it to mandatory if at least one of its members is mandatory. 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen group_message.policy_options.mode = cp.PolicyOptions.RECOMMENDED 41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # Indicates if at least one field was set in |group_message|. 41172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen got_fields = False 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # Iterate over fields of the message and feed them from the 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen # policy config file. 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for field in group_message.DESCRIPTOR.fields: 41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen field_value = None 41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if field.name in policies['mandatory']: 41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen group_message.policy_options.mode = cp.PolicyOptions.MANDATORY 41872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen field_value = policies['mandatory'][field.name] 41972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen elif field.name in policies['recommended']: 42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen field_value = policies['recommended'][field.name] 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if field_value != None: 42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen got_fields = True 42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen self.SetProtobufMessageField(group_message, field, field_value) 42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if got_fields: 42572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen settings.__getattribute__(group.name).CopyFrom(group_message) 42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 427dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def ProcessCloudPolicy(self, msg): 42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen """Handles a cloud policy request. (New protocol for policy requests.) 42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Checks for authorization, encodes the policy into protobuf representation, 43172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen signs it and constructs the repsonse. 43272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 43372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Args: 43472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen msg: The CloudPolicyRequest message received from the client. 43572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 43672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Returns: 43772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen A tuple of HTTP status code and response data to send to the client. 43872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen """ 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen token_info, error = self.CheckToken() 441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if not token_info: 442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return error 44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Response is only given if the scope is specified in the config file. 445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Normally 'google/chromeos/device' and 'google/chromeos/user' should be 446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # accepted. 447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_value = '' 448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (msg.policy_type in token_info['allowed_policy_types'] and 449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen msg.policy_type in self._server.policy): 450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if msg.policy_type == 'google/chromeos/user': 451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen settings = cp.CloudPolicySettings() 452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.GatherUserPolicySettings(settings, 453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self._server.policy[msg.policy_type]) 454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_value = settings.SerializeToString() 455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen elif msg.policy_type == 'google/chromeos/device': 456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen settings = dp.ChromeDeviceSettingsProto() 457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.GatherDevicePolicySettings(settings, 458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self._server.policy[msg.policy_type]) 459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_value = settings.SerializeToString() 460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Figure out the key we want to use. If multiple keys are configured, the 462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # server will rotate through them in a round-robin fashion. 463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signing_key = None 464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen req_key = None 465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen key_version = 1 466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen nkeys = len(self._server.keys) 467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and nkeys > 0: 468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if msg.public_key_version in range(1, nkeys + 1): 469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # requested key exists, use for signing and rotate. 470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen req_key = self._server.keys[msg.public_key_version - 1]['private_key'] 471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen key_version = (msg.public_key_version % nkeys) + 1 472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signing_key = self._server.keys[key_version - 1] 473ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Fill the policy data protobuf. 475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data = dm.PolicyData() 476dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.policy_type = msg.policy_type 477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.timestamp = int(time.time() * 1000) 478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.request_token = token_info['device_token']; 479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_data.policy_value = policy_value 480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen policy_data.machine_name = token_info['machine_name'] 481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if signing_key: 482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_data.public_key_version = key_version 483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_data.username = self._server.username 484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen policy_data.device_id = token_info['device_id'] 485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen signed_data = policy_data.SerializeToString() 48672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 48772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen response = dm.DeviceManagementResponse() 488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen fetch_response = response.policy_response.response.add() 489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen fetch_response.policy_data = signed_data 490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if signing_key: 491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fetch_response.policy_data_signature = ( 492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signing_key['private_key'].hashAndSign(signed_data).tostring()) 493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if msg.public_key_version != key_version: 494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fetch_response.new_public_key = signing_key['public_key'] 495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if req_key: 496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fetch_response.new_public_key_signature = ( 497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen req_key.hashAndSign(fetch_response.new_public_key).tostring()) 49872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 49972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen self.DumpMessage('Response', response) 50072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 50172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return (200, response.SerializeToString()) 50272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 5034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def CheckToken(self): 5044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Helper for checking whether the client supplied a valid DM token. 5054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Extracts the token from the request and passed to the server in order to 507dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen look up the client. 5084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen A pair of token information record and error response. If the first 511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen element is None, then the second contains an error code to send back to 512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen the client. Otherwise the first element is the same structure that is 513dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen returned by LookupToken(). 5144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 5154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch error = None 516201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch dmtoken = None 517201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch request_device_id = self.GetUniqueParam('deviceid') 5184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch match = re.match('GoogleDMToken token=(\\w+)', 5194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self._headers.getheader('Authorization', '')) 5204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if match: 5214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch dmtoken = match.group(1) 522201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if not dmtoken: 523201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch error = dm.DeviceManagementResponse.DEVICE_MANAGEMENT_TOKEN_INVALID 524201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch else: 525dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen token_info = self._server.LookupToken(dmtoken) 526dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (not token_info or 527dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen not request_device_id or 528dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen token_info['device_id'] != request_device_id): 529dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen error = dm.DeviceManagementResponse.DEVICE_NOT_FOUND 530dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen else: 531dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return (token_info, None) 5324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response = dm.DeviceManagementResponse() 5344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response.error = error 5354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.DumpMessage('Response', response) 5374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (None, (200, response.SerializeToString())) 5394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def DumpMessage(self, label, msg): 5414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Helper for logging an ASCII dump of a protobuf message.""" 5424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch logging.debug('%s\n%s' % (label, str(msg))) 5434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass TestServer(object): 5454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Handles requests and keeps global service state.""" 5464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen def __init__(self, policy_path, private_key_paths, policy_user): 5484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Initializes the server. 5494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 5514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch policy_path: Names the file to read JSON-formatted policy from. 552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private_key_paths: List of paths to read private keys from. 5534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 554dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen self._registered_tokens = {} 5554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.policy = {} 556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # There is no way to for the testserver to know the user name belonging to 558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # the GAIA auth token we received (short of actually talking to GAIA). To 559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # address this, we have a command line parameter to set the username that 560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # the server should report to the client. 561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.username = policy_user 562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 5634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if json is None: 5644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch print 'No JSON module, cannot parse policy information' 5654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch else : 5664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch try: 5674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch self.policy = json.loads(open(policy_path).read()) 5684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch except IOError: 5694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch print 'Failed to load policy from %s' % policy_path 5704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.keys = [] 572ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if private_key_paths: 573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Load specified keys from the filesystem. 574ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for key_path in private_key_paths: 575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen try: 576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen key = tlslite.api.parsePEMKey(open(key_path).read(), private=True) 577ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen except IOError: 578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen print 'Failed to load private key from %s' % key_path 579ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen continue 580ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen assert key != None 582ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.keys.append({ 'private_key' : key }) 583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else: 584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Generate a key if none were specified. 585ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen key = tlslite.api.generateRSAKey(1024) 586ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen assert key != None 587ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen self.keys.append({ 'private_key' : key }) 588ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 589ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen # Derive the public keys from the loaded private keys. 590ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for entry in self.keys: 591ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen key = entry['private_key'] 592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen algorithm = asn1der.Sequence( 594ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen [ asn1der.Data(asn1der.OBJECT_IDENTIFIER, PKCS1_RSA_OID), 595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen asn1der.Data(asn1der.NULL, '') ]) 596ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen rsa_pubkey = asn1der.Sequence([ asn1der.Integer(key.n), 597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen asn1der.Integer(key.e) ]) 598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen pubkey = asn1der.Sequence([ algorithm, asn1der.Bitstring(rsa_pubkey) ]) 599ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry['public_key'] = pubkey; 60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 6014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def HandleRequest(self, path, headers, request): 6024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Handles a request. 6034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 6054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch path: The request path and query parameters received from the client. 6064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch headers: A rfc822.Message-like object containing HTTP headers. 6074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch request: The request data received from the client as a string. 6084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 6094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch A pair of HTTP status code and response data to send to the client. 6104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 6114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch handler = RequestHandler(self, path, headers, request) 6124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return handler.HandleRequest() 6134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 614dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def RegisterDevice(self, device_id, machine_id, type): 615dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """Registers a device or user and generates a DM token for it. 6164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 6184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch device_id: The device identifier provided by the client. 6194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 6214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch The newly generated device token for the device. 6224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 6234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch dmtoken_chars = [] 6244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch while len(dmtoken_chars) < 32: 6254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch dmtoken_chars.append(random.choice('0123456789abcdef')) 626dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dmtoken = ''.join(dmtoken_chars) 627dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen allowed_policy_types = { 628dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dm.DeviceRegisterRequest.USER: ['google/chromeos/user'], 629dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dm.DeviceRegisterRequest.DEVICE: ['google/chromeos/device'], 630dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dm.DeviceRegisterRequest.TT: ['google/chromeos/user'], 631dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 632dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen self._registered_tokens[dmtoken] = { 633dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 'device_id': device_id, 634dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 'device_token': dmtoken, 635dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 'allowed_policy_types': allowed_policy_types[type], 636dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 'machine_name': 'chromeos-' + machine_id, 637dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 638dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self._registered_tokens[dmtoken] 639dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 640dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen def LookupToken(self, dmtoken): 641dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen """Looks up a device or a user by DM token. 6424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 6444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch dmtoken: The device management token provided by the client. 6454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Returns: 647dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen A dictionary with information about a device or user that is registered by 648dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen dmtoken, or None if the token is not found. 6494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 650dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return self._registered_tokens.get(dmtoken, None) 6514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch def UnregisterDevice(self, dmtoken): 6534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """Unregisters a device identified by the given DM token. 6544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 6554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Args: 6564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch dmtoken: The device management token provided by the client. 6574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch """ 658dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if dmtoken in self._registered_tokens.keys(): 659dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen del self._registered_tokens[dmtoken] 660