From 7c720e61c5d3475111a80227268e7ef2af798936 Mon Sep 17 00:00:00 2001 From: Victor Vrantchan Date: Thu, 8 Aug 2019 22:32:05 -0400 Subject: [PATCH] add assign profile endpoint (#611) Adds the ability to send a POST request to assign one or more serials to a profile ID that was defined with the define profile endpoint. POST /v1/dep/assign { "id" : "profile_id", "serials" : [a,b,c,d] } --- platform/dep/assign_profile.go | 64 ++++++++++++++++++++++++++++++++++ platform/dep/client.go | 12 +++++++ platform/dep/server.go | 10 ++++++ platform/dep/service.go | 1 + 4 files changed, 87 insertions(+) create mode 100644 platform/dep/assign_profile.go diff --git a/platform/dep/assign_profile.go b/platform/dep/assign_profile.go new file mode 100644 index 00000000..7e8d88af --- /dev/null +++ b/platform/dep/assign_profile.go @@ -0,0 +1,64 @@ +package dep + +import ( + "context" + "errors" + "net/http" + + "github.com/go-kit/kit/endpoint" + + "github.com/micromdm/micromdm/dep" + "github.com/micromdm/micromdm/pkg/httputil" +) + +func (svc *DEPService) AssignProfile(ctx context.Context, id string, serials ...string) (*dep.ProfileResponse, error) { + if svc.client == nil { + return nil, errors.New("DEP not configured yet. add a DEP token to enable DEP") + } + return svc.client.AssignProfile(id, serials...) +} + +type assignProfileRequest struct { + ID string `json:"id"` + Serials []string `json:"serials"` +} + +type assignProfileResponse struct { + *dep.ProfileResponse + Err error `json:"err,omitempty"` +} + +func (r assignProfileResponse) Failed() error { return r.Err } + +func decodeAssignProfileRequest(ctx context.Context, r *http.Request) (interface{}, error) { + var req assignProfileRequest + err := httputil.DecodeJSONRequest(r, &req) + return req, err +} + +func decodeAssignProfileResponse(_ context.Context, r *http.Response) (interface{}, error) { + var resp assignProfileResponse + err := httputil.DecodeJSONResponse(r, &resp) + return resp, err +} + +func MakeAssignProfileEndpoint(svc Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (response interface{}, err error) { + req := request.(assignProfileRequest) + resp, err := svc.AssignProfile(ctx, req.ID, req.Serials...) + return &assignProfileResponse{ + ProfileResponse: resp, + Err: err, + }, nil + } +} + +func (e Endpoints) AssignProfile(ctx context.Context, id string, serials ...string) (*dep.ProfileResponse, error) { + request := assignProfileRequest{ID: id, Serials: serials} + resp, err := e.AssignProfileEndpoint(ctx, request) + if err != nil { + return nil, err + } + response := resp.(assignProfileResponse) + return response.ProfileResponse, response.Err +} diff --git a/platform/dep/client.go b/platform/dep/client.go index 0496fd26..d45fdb71 100644 --- a/platform/dep/client.go +++ b/platform/dep/client.go @@ -27,6 +27,17 @@ func NewHTTPClient(instance, token string, logger log.Logger, opts ...httptransp ).Endpoint() } + var assignProfileEndpoint endpoint.Endpoint + { + assignProfileEndpoint = httptransport.NewClient( + "POST", + httputil.CopyURL(u, "/v1/dep/assign"), + httputil.EncodeRequestWithToken(token, httptransport.EncodeJSONRequest), + decodeAssignProfileResponse, + opts..., + ).Endpoint() + } + var fetchProfileEndpoint endpoint.Endpoint { fetchProfileEndpoint = httptransport.NewClient( @@ -62,6 +73,7 @@ func NewHTTPClient(instance, token string, logger log.Logger, opts ...httptransp return Endpoints{ DefineProfileEndpoint: defineProfileEndpoint, + AssignProfileEndpoint: assignProfileEndpoint, FetchProfileEndpoint: fetchProfileEndpoint, GetAccountInfoEndpoint: getAccountInfoEndpoint, GetDeviceDetailsEndpoint: getDeviceDetailsEndpoint, diff --git a/platform/dep/server.go b/platform/dep/server.go index 9ad5f2eb..2976eb9c 100644 --- a/platform/dep/server.go +++ b/platform/dep/server.go @@ -13,10 +13,12 @@ type Endpoints struct { FetchProfileEndpoint endpoint.Endpoint GetAccountInfoEndpoint endpoint.Endpoint GetDeviceDetailsEndpoint endpoint.Endpoint + AssignProfileEndpoint endpoint.Endpoint } func MakeServerEndpoints(s Service, outer endpoint.Middleware, others ...endpoint.Middleware) Endpoints { return Endpoints{ + AssignProfileEndpoint: endpoint.Chain(outer, others...)(MakeAssignProfileEndpoint(s)), DefineProfileEndpoint: endpoint.Chain(outer, others...)(MakeDefineProfileEndpoint(s)), FetchProfileEndpoint: endpoint.Chain(outer, others...)(MakeFetchProfileEndpoint(s)), GetAccountInfoEndpoint: endpoint.Chain(outer, others...)(MakeGetAccountInfoEndpoint(s)), @@ -29,6 +31,7 @@ func RegisterHTTPHandlers(r *mux.Router, e Endpoints, options ...httptransport.S // POST /v1/dep/profiles get a DEP profile given a known profile UUID // GET /v1/dep/account get information about the dep account // POST /v1/dep/devices get device details given a list of serials + // POST /v1/dep/assign assign a specific profile ID to one or more serial r.Methods("PUT").Path("/v1/dep/profiles").Handler(httptransport.NewServer( e.DefineProfileEndpoint, @@ -37,6 +40,13 @@ func RegisterHTTPHandlers(r *mux.Router, e Endpoints, options ...httptransport.S options..., )) + r.Methods("POST").Path("/v1/dep/assign").Handler(httptransport.NewServer( + e.AssignProfileEndpoint, + decodeAssignProfileRequest, + httputil.EncodeJSONResponse, + options..., + )) + r.Methods("POST").Path("/v1/dep/profiles").Handler(httptransport.NewServer( e.FetchProfileEndpoint, decodeFetchProfileRequest, diff --git a/platform/dep/service.go b/platform/dep/service.go index 33adf95d..2b0ee929 100644 --- a/platform/dep/service.go +++ b/platform/dep/service.go @@ -10,6 +10,7 @@ import ( type Service interface { DefineProfile(ctx context.Context, p *dep.Profile) (*dep.ProfileResponse, error) + AssignProfile(ctx context.Context, uuid string, serials ...string) (*dep.ProfileResponse, error) GetAccountInfo(ctx context.Context) (*dep.Account, error) GetDeviceDetails(ctx context.Context, serials []string) (*dep.DeviceDetailsResponse, error) FetchProfile(ctx context.Context, uuid string) (*dep.Profile, error)