first commit in new package

This commit is contained in:
Victor Vrantchan
2017-01-25 13:30:53 -05:00
parent 0dc1a18eea
commit 28219fcec2
60 changed files with 3942 additions and 0 deletions

30
enroll/endpoint.go Normal file
View File

@@ -0,0 +1,30 @@
package enroll
import (
"github.com/go-kit/kit/endpoint"
"golang.org/x/net/context"
)
type Endpoints struct {
GetEnrollEndpoint endpoint.Endpoint
}
type mdmEnrollRequest struct{}
type mdmEnrollResponse struct {
Profile
Err error `plist:"error,omitempty"`
}
func MakeServerEndpoints(s Service) Endpoints {
return Endpoints{
GetEnrollEndpoint: MakeGetEnrollEndpoint(s),
}
}
func MakeGetEnrollEndpoint(s Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
profile, err := s.Enroll(ctx)
return mdmEnrollResponse{profile, err}, nil
}
}

78
enroll/profile.go Normal file
View File

@@ -0,0 +1,78 @@
package enroll
import (
"github.com/satori/go.uuid"
"time"
)
type Payload struct {
PayloadType string `json:"type" db:"type"`
PayloadVersion int `json:"version" db:"version"`
PayloadIdentifier string `json:"identifier" db:"identifier"`
PayloadUUID string `json:"uuid" db:"uuid"`
PayloadDisplayName string `json:"displayname" db:"displayname"`
PayloadDescription string `json:"description,omitempty" db:"description"`
PayloadOrganization string `json:"organization,omitempty" db:"organization"`
PayloadScope string `json:"scope" db:"scope" plist:",omitempty"`
PayloadContent interface{} `json:"content,omitempty" plist:"PayloadContent,omitempty"`
}
type Profile struct {
PayloadContent []interface{} `json:"content,omitempty" db:"content"`
PayloadDescription string `json:"description,omitempty" db:"description"`
PayloadDisplayName string `json:"displayname,omitempty" db:"displayname"`
PayloadExpirationDate *time.Time `json:"expiration_date,omitempty" db:"expiration_date" plist:",omitempty"`
PayloadIdentifier string `json:"identifier" db:"identifier"`
PayloadOrganization string `json:"organization,omitempty" db:"organization"`
PayloadUUID string `json:"uuid" db:"uuid"`
PayloadRemovalDisallowed bool `json:"removal_disallowed" db:"removal_disallowed" plist:",omitempty"`
PayloadType string `json:"type" db:"type"`
PayloadVersion int `json:"version" db:"version"`
PayloadScope string `json:"scope" db:"scope" plist:",omitempty"`
RemovalDate *time.Time `json:"removal_date" db:"removal_date" plist:"-" plist:",omitempty"`
DurationUntilRemoval float32 `json:"duration_until_removal" db:"duration_until_removal" plist:",omitempty"`
ConsentText map[string]string `json:"consent_text" db:"consent_text" plist:",omitempty"`
}
func NewProfile() *Profile {
payloadUuid := uuid.NewV4()
return &Profile{
PayloadVersion: 1,
PayloadType: "Configuration",
PayloadUUID: payloadUuid.String(),
}
}
func NewPayload(payloadType string) *Payload {
payloadUuid := uuid.NewV4()
return &Payload{
PayloadVersion: 1,
PayloadType: payloadType,
PayloadUUID: payloadUuid.String(),
}
}
type SCEPPayloadContent struct {
CAFingerprint []byte `plist:"CAFingerprint,omitempty"` // NSData
Challenge string `plist:"Challenge,omitempty"`
Keysize int
KeyType string `plist:"Key Type"`
KeyUsage int `plist:"Key Usage"`
Name string
Subject [][][]string `plist:"Subject,omitempty"`
URL string
}
// TODO: Actually this is one of those non-nested payloads that doesnt respect the PayloadContent key.
type MDMPayloadContent struct {
Payload
AccessRights int
CheckInURL string
CheckOutWhenRemoved bool
IdentityCertificateUUID string
ServerCapabilities []string `plist:"ServerCapabilities,omitempty"`
ServerURL string
Topic string
}

146
enroll/service.go Normal file
View File

@@ -0,0 +1,146 @@
package enroll
import (
"golang.org/x/net/context"
"io/ioutil"
"strings"
)
type Service interface {
Enroll(ctx context.Context) (Profile, error)
}
func NewService(pushTopic, caCertPath, scepURL, scepChallenge, url, tlsCertPath, scepSubject string) (Service, error) {
var caCert, tlsCert []byte
var err error
if caCertPath != "" {
caCert, err = ioutil.ReadFile(caCertPath)
if err != nil {
return nil, err
}
}
if tlsCertPath != "" {
tlsCert, err = ioutil.ReadFile(tlsCertPath)
if err != nil {
return nil, err
}
}
if scepSubject == "" {
scepSubject = "/O=MicroMDM/CN=MicroMDM Identity (%ComputerName%)"
}
subjectElements := strings.Split(scepSubject, "/")
var subject [][][]string
for _, element := range subjectElements {
if element == "" {
continue
}
subjectKeyValue := strings.Split(element, "=")
subject = append(subject, [][]string{[]string{subjectKeyValue[0], subjectKeyValue[1]}})
}
return &service{
URL: url,
SCEPURL: scepURL,
SCEPSubject: subject,
SCEPChallenge: scepChallenge,
Topic: pushTopic,
CACert: caCert,
TLSCert: tlsCert,
}, nil
}
type service struct {
URL string
SCEPURL string
SCEPChallenge string
SCEPSubject [][][]string
Topic string // APNS Topic for MDM notifications
CACert []byte
TLSCert []byte
}
func (svc service) Enroll(ctx context.Context) (Profile, error) {
profile := NewProfile()
profile.PayloadIdentifier = "com.github.micromdm.micromdm.mdm"
profile.PayloadOrganization = "MicroMDM"
profile.PayloadDisplayName = "Enrollment Profile"
profile.PayloadDescription = "The server may alter your settings"
profile.PayloadScope = "System"
mdmPayload := NewPayload("com.apple.mdm")
mdmPayload.PayloadDescription = "Enrolls with the MDM server"
mdmPayload.PayloadOrganization = "MicroMDM"
mdmPayload.PayloadIdentifier = "com.github.micromdm.mdm"
mdmPayload.PayloadScope = "System"
mdmPayloadContent := MDMPayloadContent{
Payload: *mdmPayload,
AccessRights: 8191,
CheckInURL: svc.URL + "/mdm/checkin",
CheckOutWhenRemoved: true,
ServerURL: svc.URL + "/mdm/connect",
Topic: svc.Topic,
}
payloadContent := []interface{}{}
if svc.SCEPURL != "" {
scepContent := SCEPPayloadContent{
URL: svc.SCEPURL,
Keysize: 1024,
KeyType: "RSA",
KeyUsage: 0,
Name: "Device Management Identity Certificate",
Subject: svc.SCEPSubject,
}
if svc.SCEPChallenge != "" {
scepContent.Challenge = svc.SCEPChallenge
}
scepPayload := NewPayload("com.apple.security.scep")
scepPayload.PayloadDescription = "Configures SCEP"
scepPayload.PayloadDisplayName = "SCEP"
scepPayload.PayloadIdentifier = "com.github.micromdm.scep"
scepPayload.PayloadOrganization = "MicroMDM"
scepPayload.PayloadContent = scepContent
scepPayload.PayloadScope = "System"
payloadContent = append(payloadContent, *scepPayload)
mdmPayloadContent.IdentityCertificateUUID = scepPayload.PayloadUUID
}
payloadContent = append(payloadContent, mdmPayloadContent)
if len(svc.CACert) > 0 {
caPayload := NewPayload("com.apple.security.root")
caPayload.PayloadDisplayName = "Root certificate for MicroMDM"
caPayload.PayloadDescription = "Installs the root CA certificate for MicroMDM"
caPayload.PayloadIdentifier = "com.github.micromdm.ssl.ca"
caPayload.PayloadContent = svc.CACert
payloadContent = append(payloadContent, *caPayload)
}
// Client needs to trust us at this point if we are using a self signed certificate.
if len(svc.TLSCert) > 0 {
tlsPayload := NewPayload("com.apple.security.pkcs1")
tlsPayload.PayloadDisplayName = "Self-signed TLS certificate for MicroMDM"
tlsPayload.PayloadDescription = "Installs the TLS certificate for MicroMDM"
tlsPayload.PayloadIdentifier = "com.github.micromdm.tls"
tlsPayload.PayloadContent = svc.TLSCert
payloadContent = append(payloadContent, *tlsPayload)
}
profile.PayloadContent = payloadContent
return *profile, nil
}

47
enroll/transport.go Normal file
View File

@@ -0,0 +1,47 @@
package enroll
import (
"net/http"
"golang.org/x/net/context"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/gorilla/mux"
"github.com/groob/plist"
)
// ServiceHandler returns an HTTP Handler for the enroll service
func ServiceHandler(ctx context.Context, svc Service, logger log.Logger) http.Handler {
r := mux.NewRouter()
e := MakeServerEndpoints(svc)
opts := []httptransport.ServerOption{
httptransport.ServerErrorLogger(logger),
}
r.Methods("GET").Path("/mdm/enroll").Handler(httptransport.NewServer(
ctx,
e.GetEnrollEndpoint,
decodeMDMEnrollRequest,
encodeResponse,
opts...,
))
return r
}
func decodeMDMEnrollRequest(_ context.Context, r *http.Request) (interface{}, error) {
return r, nil
}
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
resp := response.(mdmEnrollResponse)
w.Header().Set("Content-Type", "application/x-apple-aspen-config")
if err := plist.NewEncoder(w).Encode(resp); err != nil {
return err
}
return nil
}