mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-10 03:16:07 +08:00
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:
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
type Certificate struct {
|
type Certificate struct {
|
||||||
UUID string `db:"certificate_uuid" json:"uuid"`
|
UUID string `db:"certificate_uuid" json:"uuid"`
|
||||||
|
DeviceUUID string `db:"device_uuid" json:"device_uuid"`
|
||||||
Data x509.Certificate `db:"data" json:"data"`
|
Data x509.Certificate `db:"data" json:"data"`
|
||||||
CommonName string `db:"common_name" json:"common_nane"`
|
CommonName string `db:"common_name" json:"common_nane"`
|
||||||
IsIdentity bool `db:"is_identity" json:"is_identity"`
|
IsIdentity bool `db:"is_identity" json:"is_identity"`
|
||||||
|
|||||||
@@ -11,25 +11,38 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
insertCertificateStmt = `INSERT INTO certificates (
|
insertCertificateStmt = `INSERT INTO devices_certificates (
|
||||||
|
device_uuid,
|
||||||
common_name,
|
common_name,
|
||||||
data,
|
data,
|
||||||
is_identity
|
is_identity
|
||||||
) VALUES ($1, $2, $3)
|
) VALUES ($1, $2, $3, $4)
|
||||||
RETURNING certificate_uuid;`
|
RETURNING certificate_uuid;`
|
||||||
|
|
||||||
selectCertificatesStmt = `SELECT
|
selectCertificatesStmt = `SELECT
|
||||||
certificate_uuid,
|
certificate_uuid,
|
||||||
|
device_uuid
|
||||||
common_name,
|
common_name,
|
||||||
data,
|
data,
|
||||||
is_identity
|
is_identity
|
||||||
FROM certificates`
|
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.
|
// This Datastore manages a list of certificates assigned to devices.
|
||||||
type Datastore interface {
|
type Datastore interface {
|
||||||
New(crt *Certificate) (string, error)
|
New(crt *Certificate) (string, error)
|
||||||
Certificates(params ...interface{}) ([]Certificate, error)
|
Certificates(params ...interface{}) ([]Certificate, error)
|
||||||
|
GetCertificatesByDeviceUDID(udid string) ([]Certificate, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type pgStore struct {
|
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) {
|
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
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +94,15 @@ func (store pgStore) Certificates(params ...interface{}) ([]Certificate, error)
|
|||||||
return certificates, nil
|
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
|
// UUID is a filter that can be added as a parameter to narrow down the list of returned results
|
||||||
type UUID struct {
|
type UUID struct {
|
||||||
UUID string
|
UUID string
|
||||||
@@ -90,6 +112,15 @@ func (p UUID) where() string {
|
|||||||
return fmt.Sprintf("certificate_uuid = '%s'", p.UUID)
|
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
|
// whereer is for building args passed into a method which finds resources
|
||||||
type whereer interface {
|
type whereer interface {
|
||||||
where() string
|
where() string
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/micromdm/mdm"
|
"github.com/micromdm/mdm"
|
||||||
apps "github.com/micromdm/micromdm/applications"
|
apps "github.com/micromdm/micromdm/applications"
|
||||||
|
"github.com/micromdm/micromdm/certificates"
|
||||||
"github.com/micromdm/micromdm/command"
|
"github.com/micromdm/micromdm/command"
|
||||||
"github.com/micromdm/micromdm/device"
|
"github.com/micromdm/micromdm/device"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -21,11 +22,12 @@ type Service interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewService creates a mdm service
|
// 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{
|
return &service{
|
||||||
commands: cs,
|
commands: cs,
|
||||||
devices: devices,
|
devices: devices,
|
||||||
apps: apps,
|
apps: apps,
|
||||||
|
certs: certs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ type service struct {
|
|||||||
devices device.Datastore
|
devices device.Datastore
|
||||||
apps apps.Datastore
|
apps apps.Datastore
|
||||||
commands command.Service
|
commands command.Service
|
||||||
|
certs certificates.Datastore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acknowledge a response from a device.
|
// Acknowledge a response from a device.
|
||||||
@@ -46,11 +49,12 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
|
|||||||
}
|
}
|
||||||
case "InstalledApplicationList":
|
case "InstalledApplicationList":
|
||||||
if err := svc.ackInstalledApplicationList(req); err != nil {
|
if err := svc.ackInstalledApplicationList(req); err != nil {
|
||||||
fmt.Printf("Got an error acknowledging InstalledApplicationList: %v\n", err)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
case "CertificateList":
|
case "CertificateList":
|
||||||
return 0, nil
|
if err := svc.ackCertificateList(req); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Need to handle the absence of RequestType in IOS8 devices
|
// Need to handle the absence of RequestType in IOS8 devices
|
||||||
if req.QueryResponses.UDID != "" {
|
if req.QueryResponses.UDID != "" {
|
||||||
@@ -64,6 +68,12 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
|
|||||||
return 0, err
|
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)
|
total, err := svc.commands.DeleteCommand(req.UDID, req.CommandUUID)
|
||||||
@@ -237,10 +247,24 @@ skip:
|
|||||||
|
|
||||||
// Acknowledge a response to `CertificateList`.
|
// Acknowledge a response to `CertificateList`.
|
||||||
func (svc service) ackCertificateList(req mdm.Response) error {
|
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 {
|
if err != nil {
|
||||||
return errors.Wrap(err, "getting a device record by udid")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
6
main.go
6
main.go
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
"github.com/micromdm/dep"
|
"github.com/micromdm/dep"
|
||||||
"github.com/micromdm/micromdm/applications"
|
"github.com/micromdm/micromdm/applications"
|
||||||
|
"github.com/micromdm/micromdm/certificates"
|
||||||
"github.com/micromdm/micromdm/checkin"
|
"github.com/micromdm/micromdm/checkin"
|
||||||
"github.com/micromdm/micromdm/command"
|
"github.com/micromdm/micromdm/command"
|
||||||
"github.com/micromdm/micromdm/connect"
|
"github.com/micromdm/micromdm/connect"
|
||||||
@@ -200,11 +201,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dc := depClient(logger, *flDEPCK, *flDEPCS, *flDEPAT, *flDEPAS, *flDEPServerURL, *flDEPsim)
|
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)
|
commandSvc := command.NewService(commandDB)
|
||||||
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
|
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
|
||||||
connectSvc := connect.NewService(deviceDB, commandSvc)
|
connectSvc := connect.NewService(deviceDB, appsDB, certsDB, commandSvc)
|
||||||
connectSvc := connect.NewService(deviceDB, appsDB, commandSvc)
|
|
||||||
enrollSvc, _ := enroll.NewService(*flPushCert, *flPushPass, *flTLSCACert, *flSCEPURL, *flURL)
|
enrollSvc, _ := enroll.NewService(*flPushCert, *flPushPass, *flTLSCACert, *flSCEPURL, *flURL)
|
||||||
|
|
||||||
httpLogger := log.NewContext(logger).With("component", "http")
|
httpLogger := log.NewContext(logger).With("component", "http")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/RobotsAndPencils/buford/push"
|
"github.com/RobotsAndPencils/buford/push"
|
||||||
"github.com/micromdm/dep"
|
"github.com/micromdm/dep"
|
||||||
"github.com/micromdm/micromdm/applications"
|
"github.com/micromdm/micromdm/applications"
|
||||||
|
"github.com/micromdm/micromdm/certificates"
|
||||||
"github.com/micromdm/micromdm/device"
|
"github.com/micromdm/micromdm/device"
|
||||||
"github.com/micromdm/micromdm/workflow"
|
"github.com/micromdm/micromdm/workflow"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -31,6 +32,9 @@ type Service interface {
|
|||||||
// Installed Applications
|
// Installed Applications
|
||||||
InstalledApps(deviceUUID string) ([]applications.Application, error)
|
InstalledApps(deviceUUID string) ([]applications.Application, error)
|
||||||
|
|
||||||
|
// Installed Certificates
|
||||||
|
Certificates(deviceUUID string) ([]certificates.Certificate, error)
|
||||||
|
|
||||||
// AssignWorkflow assigns a workflow to a device
|
// AssignWorkflow assigns a workflow to a device
|
||||||
AssignWorkflow(deviceUUID, workflowUUID string) error
|
AssignWorkflow(deviceUUID, workflowUUID string) error
|
||||||
|
|
||||||
@@ -43,13 +47,14 @@ type Service interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewService creates a management service
|
// 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{
|
return &service{
|
||||||
devices: ds,
|
devices: ds,
|
||||||
depClient: dc,
|
depClient: dc,
|
||||||
workflows: ws,
|
workflows: ws,
|
||||||
pushsvc: ps,
|
pushsvc: ps,
|
||||||
applications: as,
|
applications: as,
|
||||||
|
certificates: cs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +64,7 @@ type service struct {
|
|||||||
workflows workflow.Datastore
|
workflows workflow.Datastore
|
||||||
pushsvc *push.Service
|
pushsvc *push.Service
|
||||||
applications applications.Datastore
|
applications applications.Datastore
|
||||||
|
certificates certificates.Datastore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc service) Push(deviceUDID string) (string, error) {
|
func (svc service) Push(deviceUDID string) (string, error) {
|
||||||
@@ -173,3 +179,12 @@ func (svc service) InstalledApps(deviceUUID string) ([]applications.Application,
|
|||||||
|
|
||||||
return apps, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
|
|||||||
encodeResponse,
|
encodeResponse,
|
||||||
opts...,
|
opts...,
|
||||||
)
|
)
|
||||||
|
certificatesHandler := kithttp.NewServer(
|
||||||
|
ctx,
|
||||||
|
makeCertificatesEndpoint(svc),
|
||||||
|
decodeCertificatesRequest,
|
||||||
|
encodeResponse,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
|
||||||
r := mux.NewRouter()
|
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/{uuid}", updateDeviceHandler).Methods("PATCH")
|
||||||
r.Handle("/management/v1/devices/{udid}/push", pushHandler).Methods("POST")
|
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}/applications", installedAppsHandler).Methods("GET")
|
||||||
|
r.Handle("/management/v1/devices/{uuid}/certificates", certificatesHandler).Methods("GET")
|
||||||
// profiles
|
// profiles
|
||||||
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
||||||
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
||||||
@@ -246,6 +254,21 @@ func decodeInstalledAppsRequest(_ context.Context, r *http.Request) (interface{}
|
|||||||
return request, nil
|
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 {
|
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
||||||
if e, ok := response.(errorer); ok && e.error() != nil {
|
if e, ok := response.(errorer); ok && e.error() != nil {
|
||||||
encodeError(ctx, e.error(), w)
|
encodeError(ctx, e.error(), w)
|
||||||
|
|||||||
Reference in New Issue
Block a user