Add device uuid to certificate, as there will never be a normalised form of the certificate data.

Change statments to reflect table change from certificates to devices_certificates
Add the CertificateList request type to the connect service's Acknowledge method
Add certificates datastore to the management service, and add endpoints and request/responses for retrieving certificates by device uuid to the management endpoujnt.
This commit is contained in:
Mosen
2016-07-19 21:39:43 +10:00
parent 8bc2fc749b
commit c723c80118
6 changed files with 105 additions and 11 deletions

View File

@@ -6,6 +6,7 @@ import (
type Certificate struct {
UUID string `db:"certificate_uuid" json:"uuid"`
DeviceUUID string `db:"device_uuid" json:"device_uuid"`
Data x509.Certificate `db:"data" json:"data"`
CommonName string `db:"common_name" json:"common_nane"`
IsIdentity bool `db:"is_identity" json:"is_identity"`

View File

@@ -11,25 +11,38 @@ import (
)
var (
insertCertificateStmt = `INSERT INTO certificates (
insertCertificateStmt = `INSERT INTO devices_certificates (
device_uuid,
common_name,
data,
is_identity
) VALUES ($1, $2, $3)
) VALUES ($1, $2, $3, $4)
RETURNING certificate_uuid;`
selectCertificatesStmt = `SELECT
certificate_uuid,
device_uuid
common_name,
data,
is_identity
FROM certificates`
selectCertificatesByDeviceStmt = `SELECT
certificate_uuid,
certificates.device_uuid device_uuid
common_name,
data,
is_identity
FROM certificates
INNER JOIN devices ON certificates.device_uuid = devices.device_uuid
WHERE devices.udid = $1`
)
// This Datastore manages a list of certificates assigned to devices.
type Datastore interface {
New(crt *Certificate) (string, error)
Certificates(params ...interface{}) ([]Certificate, error)
GetCertificatesByDeviceUDID(udid string) ([]Certificate, error)
}
type pgStore struct {
@@ -63,7 +76,7 @@ func NewDB(driver, conn string, logger kitlog.Logger) (Datastore, error) {
}
func (store pgStore) New(c *Certificate) (string, error) {
if err := store.QueryRow(insertCertificateStmt, c.CommonName, "", c.IsIdentity).Scan(&c.UUID); err != nil {
if err := store.QueryRow(insertCertificateStmt, c.DeviceUUID, c.CommonName, "", c.IsIdentity).Scan(&c.UUID); err != nil {
return "", err
}
@@ -81,6 +94,15 @@ func (store pgStore) Certificates(params ...interface{}) ([]Certificate, error)
return certificates, nil
}
func (store pgStore) GetCertificatesByDeviceUDID(udid string) ([]Certificate, error) {
var certificates []Certificate
err := store.Select(&certificates, selectCertificatesByDeviceStmt, udid)
if err != nil {
return nil, errors.Wrap(err, "pgStore GetCertificatesByDeviceUDID")
}
return certificates, nil
}
// UUID is a filter that can be added as a parameter to narrow down the list of returned results
type UUID struct {
UUID string
@@ -90,6 +112,15 @@ func (p UUID) where() string {
return fmt.Sprintf("certificate_uuid = '%s'", p.UUID)
}
// Filter by a device uuid
type DeviceUUID struct {
UUID string
}
func (p DeviceUUID) where() string {
return fmt.Sprintf("device_uuid = '%s'", p.UUID)
}
// whereer is for building args passed into a method which finds resources
type whereer interface {
where() string

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"github.com/micromdm/mdm"
apps "github.com/micromdm/micromdm/applications"
"github.com/micromdm/micromdm/certificates"
"github.com/micromdm/micromdm/command"
"github.com/micromdm/micromdm/device"
"github.com/pkg/errors"
@@ -21,11 +22,12 @@ type Service interface {
}
// NewService creates a mdm service
func NewService(devices device.Datastore, apps apps.Datastore, cs command.Service) Service {
func NewService(devices device.Datastore, apps apps.Datastore, certs certificates.Datastore, cs command.Service) Service {
return &service{
commands: cs,
devices: devices,
apps: apps,
certs: certs,
}
}
@@ -33,6 +35,7 @@ type service struct {
devices device.Datastore
apps apps.Datastore
commands command.Service
certs certificates.Datastore
}
// Acknowledge a response from a device.
@@ -46,11 +49,12 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
}
case "InstalledApplicationList":
if err := svc.ackInstalledApplicationList(req); err != nil {
fmt.Printf("Got an error acknowledging InstalledApplicationList: %v\n", err)
return 0, err
}
case "CertificateList":
return 0, nil
if err := svc.ackCertificateList(req); err != nil {
return 0, err
}
default:
// Need to handle the absence of RequestType in IOS8 devices
if req.QueryResponses.UDID != "" {
@@ -64,6 +68,12 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
return 0, err
}
}
if req.CertificateList != nil {
if err := svc.ackCertificateList(req); err != nil {
return 0, err
}
}
}
total, err := svc.commands.DeleteCommand(req.UDID, req.CommandUUID)
@@ -237,10 +247,24 @@ skip:
// Acknowledge a response to `CertificateList`.
func (svc service) ackCertificateList(req mdm.Response) error {
_, err := svc.devices.GetDeviceByUDID(req.UDID, "device_uuid")
device, err := svc.devices.GetDeviceByUDID(req.UDID, "device_uuid")
if err != nil {
return errors.Wrap(err, "getting a device record by udid")
}
for _, cert := range req.CertificateList {
newCert := certificates.Certificate{
CommonName: cert.CommonName,
IsIdentity: cert.IsIdentity,
//Data: cert.Data,
DeviceUUID: device.UUID,
}
_, err := svc.certs.New(&newCert)
if err != nil {
return errors.Wrap(err, "persisting a device certificate")
}
}
return nil
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/go-kit/kit/log"
"github.com/micromdm/dep"
"github.com/micromdm/micromdm/applications"
"github.com/micromdm/micromdm/certificates"
"github.com/micromdm/micromdm/checkin"
"github.com/micromdm/micromdm/command"
"github.com/micromdm/micromdm/connect"
@@ -200,11 +201,10 @@ func main() {
}
dc := depClient(logger, *flDEPCK, *flDEPCS, *flDEPAT, *flDEPAS, *flDEPServerURL, *flDEPsim)
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc, appsDB)
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc, appsDB, certsDB)
commandSvc := command.NewService(commandDB)
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
connectSvc := connect.NewService(deviceDB, commandSvc)
connectSvc := connect.NewService(deviceDB, appsDB, commandSvc)
connectSvc := connect.NewService(deviceDB, appsDB, certsDB, commandSvc)
enrollSvc, _ := enroll.NewService(*flPushCert, *flPushPass, *flTLSCACert, *flSCEPURL, *flURL)
httpLogger := log.NewContext(logger).With("component", "http")

View File

@@ -5,6 +5,7 @@ import (
"github.com/RobotsAndPencils/buford/push"
"github.com/micromdm/dep"
"github.com/micromdm/micromdm/applications"
"github.com/micromdm/micromdm/certificates"
"github.com/micromdm/micromdm/device"
"github.com/micromdm/micromdm/workflow"
"github.com/pkg/errors"
@@ -31,6 +32,9 @@ type Service interface {
// Installed Applications
InstalledApps(deviceUUID string) ([]applications.Application, error)
// Installed Certificates
Certificates(deviceUUID string) ([]certificates.Certificate, error)
// AssignWorkflow assigns a workflow to a device
AssignWorkflow(deviceUUID, workflowUUID string) error
@@ -43,13 +47,14 @@ type Service interface {
}
// NewService creates a management service
func NewService(ds device.Datastore, ws workflow.Datastore, dc dep.Client, ps *push.Service, as applications.Datastore) Service {
func NewService(ds device.Datastore, ws workflow.Datastore, dc dep.Client, ps *push.Service, as applications.Datastore, cs certificates.Datastore) Service {
return &service{
devices: ds,
depClient: dc,
workflows: ws,
pushsvc: ps,
applications: as,
certificates: cs,
}
}
@@ -59,6 +64,7 @@ type service struct {
workflows workflow.Datastore
pushsvc *push.Service
applications applications.Datastore
certificates certificates.Datastore
}
func (svc service) Push(deviceUDID string) (string, error) {
@@ -173,3 +179,12 @@ func (svc service) InstalledApps(deviceUUID string) ([]applications.Application,
return apps, nil
}
func (svc service) Certificates(deviceUUID string) ([]certificates.Certificate, error) {
certs, err := svc.certificates.GetCertificatesByDeviceUDID(deviceUUID)
if err != nil {
return nil, errors.Wrap(err, "management: certificates")
}
return certs, nil
}

View File

@@ -108,6 +108,13 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
encodeResponse,
opts...,
)
certificatesHandler := kithttp.NewServer(
ctx,
makeCertificatesEndpoint(svc),
decodeCertificatesRequest,
encodeResponse,
opts...,
)
r := mux.NewRouter()
@@ -119,6 +126,7 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
r.Handle("/management/v1/devices/{uuid}", updateDeviceHandler).Methods("PATCH")
r.Handle("/management/v1/devices/{udid}/push", pushHandler).Methods("POST")
r.Handle("/management/v1/devices/{uuid}/applications", installedAppsHandler).Methods("GET")
r.Handle("/management/v1/devices/{uuid}/certificates", certificatesHandler).Methods("GET")
// profiles
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
@@ -246,6 +254,21 @@ func decodeInstalledAppsRequest(_ context.Context, r *http.Request) (interface{}
return request, nil
}
func decodeCertificatesRequest(_ context.Context, r *http.Request) (interface{}, error) {
vars := mux.Vars(r)
deviceUUID, ok := vars["uuid"]
if !ok {
return nil, errBadRouting
}
var request = certificatesRequest{UUID: deviceUUID}
err := json.NewDecoder(r.Body).Decode(&request)
if err == io.EOF {
return nil, errEmptyRequest
}
return request, nil
}
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
if e, ok := response.(errorer); ok && e.error() != nil {
encodeError(ctx, e.error(), w)