def post(self, request, *args, **kwargs): self.verify_enrollment_secret() authorization = request.headers.get("Authorization") if not authorization: user_enrollment_session = UserEnrollmentSession.objects.create_from_user_enrollment( self.user_enrollment) url = "https://{}{}".format( settings["api"]["fqdn"], reverse( "mdm:authenticate_user", args=(user_enrollment_session.enrollment_secret.secret, ))) response = HttpResponse("Unauthorized", status=401) response[ "WWW-Authenticate"] = f'Bearer method="apple-as-web" url="{url}"' self.post_event("success", **user_enrollment_session.serialize_for_event()) return response else: access_token = authorization.replace("Bearer", "").strip() try: user_enrollment_session = UserEnrollmentSession.objects.get( user_enrollment=self.user_enrollment, access_token=access_token) except UserEnrollmentSession.DoesNotExist: self.abort("Invalid access token") user_enrollment_session.set_started_status() configuration_profile = build_mdm_configuration_profile( user_enrollment_session, self.user_enrollment.push_certificate) configuration_profile_filename = "zentral_mdm" self.post_event("success", **user_enrollment_session.serialize_for_event()) return build_configuration_profile_response( configuration_profile, configuration_profile_filename)
def form_valid(self, form): managed_apple_id = form.cleaned_data["managed_apple_id"] user_enrollment_session = UserEnrollmentSession.objects.create_from_user_enrollment( self.user_enrollment, managed_apple_id) return build_configuration_profile_response( build_mdm_configuration_profile( user_enrollment_session, self.user_enrollment.push_certificate), "zentral_user_enrollment")
def build_mdm_configuration_profile_response(self, dep_enrollment_session): configuration_profile = build_mdm_configuration_profile( dep_enrollment_session, dep_enrollment_session.dep_enrollment.push_certificate) configuration_profile_filename = "zentral_mdm" self.post_event("success", **dep_enrollment_session.serialize_for_event()) return build_configuration_profile_response( configuration_profile, configuration_profile_filename)
def build_mdm_configuration_profile_response(self, dep_enrollment_session): # Get the MDM push certificate push_certificate = ( dep_enrollment_session.enrollment_secret.meta_business_unit. metabusinessunitpushcertificate.push_certificate) configuration_profile = build_mdm_configuration_profile( dep_enrollment_session, push_certificate) configuration_profile_filename = "zentral_mdm" self.post_event("success", **dep_enrollment_session.serialize_for_event()) return build_configuration_profile_response( configuration_profile, configuration_profile_filename)
def post(self, request, *args, **kwargs): # Verify payload signature, extract signed payload try: certificates, payload = verify_signed_payload(request.read()) except ValueError as error: self.abort("posted data is not signed", signature_error=str(error)) for certificate_i_cn, certificate_bytes, signing_certificate in certificates: if verify_apple_iphone_device_ca_issuer_openssl(certificate_bytes): break payload = plistlib.loads(payload) self.serial_number = payload["SERIAL"] self.udid = payload["UDID"] try: es_request = verify_enrollment_secret( "dep_profile", self.kwargs["dep_profile_secret"], self.user_agent, self.ip, self.serial_number, self.udid) except EnrollmentSecretVerificationFailed as e: self.abort("secret verification failed: '{}'".format(e.err_msg)) # Start a DEP enrollment session dep_enrollment_session = DEPEnrollmentSession.objects.create_from_dep_profile( es_request.enrollment_secret.dep_profile, self.serial_number, self.udid, payload) # Get the MDM push certificate push_certificate = ( dep_enrollment_session.enrollment_secret.meta_business_unit. metabusinessunitpushcertificate.push_certificate) configuration_profile = build_mdm_configuration_profile( dep_enrollment_session, push_certificate) configuration_profile_filename = "zentral_mdm" self.post_event("success", **dep_enrollment_session.serialize_for_event()) return build_configuration_profile_response( configuration_profile, configuration_profile_filename)
def post(self, request, *args, **kwargs): # Verify payload signature, extract signed payload try: certificates, payload = verify_signed_payload(request.read()) except ValueError: self.abort("posted data is not signed") # find out which CA signed the certificate used to sign the payload # if iPhone CA: phase 2 # if SCEP CA: phase 3 for certificate_i_cn, certificate_bytes, signing_certificate in certificates: if verify_apple_iphone_device_ca_issuer(certificate_bytes): phase = 2 break elif verify_zentral_scep_ca_issuer(certificate_bytes): phase = 3 break else: self.abort( f"Unknown signing certificate issuer: {certificate_i_cn}") payload = plistlib.loads(payload) self.serial_number = payload["SERIAL"] self.udid = payload["UDID"] if phase == 2: # Verify the challenge challenge = payload.get("CHALLENGE") if not challenge: self.abort("missing challenge", phase=phase) # Pre-authenticated session ? session_enrollment = kwargs.pop("session") if session_enrollment: # running off a realm user authenticated existing ota enrollment session try: es_request = verify_enrollment_secret( "ota_enrollment_session", challenge, self.user_agent, self.ip, self.serial_number, self.udid) except EnrollmentSecretVerificationFailed as e: self.abort("secret verification failed: '{}'".format( e.err_msg), phase=phase) ota_enrollment_session = es_request.enrollment_secret.ota_enrollment_session # for PostEventMixin self.realm_user = ota_enrollment_session.realm_user # update the OTA enrollment session ota_enrollment_session.set_phase2_status( es_request, self.serial_number, self.udid) else: # running off a simple ota enrollment try: es_request = verify_enrollment_secret( "ota_enrollment", challenge, self.user_agent, self.ip, self.serial_number, self.udid) except EnrollmentSecretVerificationFailed as e: self.abort("secret verification failed: '{}'".format( e.err_msg), phase=phase) ota_enrollment = es_request.enrollment_secret.ota_enrollment if ota_enrollment.realm: self.abort( "cannot use ota enrollment secret on ota enrollment with realm", phase=phase) # Start an OTA enrollment session directly in phase 2 ota_enrollment_session = OTAEnrollmentSession.objects.create_from_machine_info( ota_enrollment, self.serial_number, self.udid) configuration_profile = build_ota_scep_configuration_profile( ota_enrollment_session) configuration_profile_filename = "zentral_ota_scep" elif phase == 3: # get the serial number from the DN of the payload signing certificate serial_number = signing_certificate.subject.get_attributes_for_oid( NameOID.SERIAL_NUMBER)[0].value if self.serial_number != serial_number: self.abort( "signing certificate DN serial number != payload serial number", phase=phase) # get the ota enrollment session from the DN of the payload signing certificate cn = signing_certificate.subject.get_attributes_for_oid( NameOID.COMMON_NAME)[0].value _, ota_enrollment_session_secret = cn.split("$") try: ota_enrollment_session = ( OTAEnrollmentSession.objects.select_for_update( ).select_related("ota_enrollment", "enrollment_secret__meta_business_unit"). get(enrollment_secret__secret=ota_enrollment_session_secret )) except OTAEnrollmentSession.DoesNotExist: self.abort( "could not find ota enrollment session from payload signing certificate", phase=phase) # for PostEventMixin self.realm_user = ota_enrollment_session.realm_user # verify and update ota enrollment session status try: ota_enrollment_session.set_phase3_status() except EnrollmentSessionStatusError: self.abort("ota enrollment session has wrong status", phase=phase) # verify DN mbu ota_enrollment_session_mbu = ota_enrollment_session.enrollment_secret.meta_business_unit o = signing_certificate.subject.get_attributes_for_oid( NameOID.ORGANIZATION_NAME)[0] if int(o.value.split("$")[-1]) != ota_enrollment_session_mbu.pk: self.abort("DN mbu doesn't match ota enrollment session mbu", phase=phase) # Get the MDM push certificate push_certificate = ota_enrollment_session.ota_enrollment.push_certificate configuration_profile = build_mdm_configuration_profile( ota_enrollment_session, push_certificate) configuration_profile_filename = "zentral_mdm" self.post_event("success", phase=phase) return build_configuration_profile_response( configuration_profile, configuration_profile_filename)