Merge pull request #892 from openziti/add.updated.at.pq

alters posture query updateAt to also indicate query state changes
This commit is contained in:
Andrew
2022-02-10 11:12:39 -05:00
committed by GitHub
31 changed files with 423 additions and 174 deletions
@@ -194,6 +194,13 @@ func MapServiceToRestModel(ae *env.AppEnv, rc *response.RequestContext, service
timeout := postureCheck.TimeoutSeconds()
timeoutRemaining := postureCheck.TimeoutRemainingSeconds(rc.ApiSession.Id, ae.Handlers.PostureResponse.PostureData(rc.Identity.Id))
//determine if updatedAt is provided by the source posture check or the posture state
if lastUpdatedAt := postureCheck.LastUpdatedAt(rc.ApiSession.Id, ae.Handlers.PostureResponse.PostureData(rc.Identity.Id)); lastUpdatedAt != nil {
if lastUpdatedAt.After(postureCheck.UpdatedAt) {
query.UpdatedAt = DateTimePtrOrNil(lastUpdatedAt)
}
}
query.IsPassing = &isCheckPassing
query.TimeoutRemaining = &timeoutRemaining
query.Timeout = &timeout
+10
View File
@@ -24,6 +24,7 @@ import (
"github.com/pkg/errors"
"go.etcd.io/bbolt"
"reflect"
"time"
)
type PostureCheck struct {
@@ -44,6 +45,9 @@ type PostureCheckSubType interface {
FailureValues(_ string, pd *PostureData) PostureCheckFailureValues
GetTimeoutSeconds() int64
GetTimeoutRemainingSeconds(apiSessionId string, pd *PostureData) int64
// LastUpdatedAt returns the last time the posture state changed or nil if not supported.
LastUpdatedAt(id string, pd *PostureData) *time.Time
}
type PostureCheckFailureValues interface {
@@ -149,3 +153,9 @@ func (entity *PostureCheck) TimeoutSeconds() int64 {
func (entity *PostureCheck) TimeoutRemainingSeconds(apiSessionId string, pd *PostureData) int64 {
return entity.SubType.GetTimeoutRemainingSeconds(apiSessionId, pd)
}
// LastUpdatedAt returns the last time posture state changed for a specific posture check.
// If the posture state does not report changes, nil is returned.
func (entity *PostureCheck) LastUpdatedAt(apiSessionId string, pd *PostureData) *time.Time {
return entity.SubType.LastUpdatedAt(apiSessionId, pd)
}
+9 -3
View File
@@ -20,6 +20,7 @@ import (
"fmt"
"github.com/openziti/edge/controller/persistence"
"go.etcd.io/bbolt"
"time"
)
var _ PostureCheckSubType = &PostureCheckMacAddresses{}
@@ -27,6 +28,11 @@ var _ PostureCheckSubType = &PostureCheckMacAddresses{}
type PostureCheckMacAddresses struct {
MacAddresses []string
}
func (p *PostureCheckMacAddresses) LastUpdatedAt(apiSessionId string, pd *PostureData) *time.Time {
return nil
}
func (p *PostureCheckMacAddresses) GetTimeoutRemainingSeconds(_ string, _ *PostureData) int64 {
return PostureCheckNoTimeout
}
@@ -37,8 +43,8 @@ func (p *PostureCheckMacAddresses) GetTimeoutSeconds() int64 {
func (p *PostureCheckMacAddresses) FailureValues(_ string, pd *PostureData) PostureCheckFailureValues {
return &PostureCheckFailureValuesMac{
ActualValue: pd.Mac.Addresses,
ExpectedValue: p.MacAddresses,
ActualValue: pd.Mac.Addresses,
ExpectedValue: p.MacAddresses,
}
}
@@ -105,4 +111,4 @@ func (p PostureCheckFailureValuesMac) Expected() interface{} {
func (p PostureCheckFailureValuesMac) Actual() interface{} {
return p.ActualValue
}
}
+24 -1
View File
@@ -41,6 +41,29 @@ type PostureCheckMfa struct {
IgnoreLegacyEndpoints bool
}
func (p *PostureCheckMfa) LastUpdatedAt(apiSessionId string, pd *PostureData) *time.Time {
apiSessionData := pd.ApiSessions[apiSessionId]
//not enough data yet
if apiSessionData == nil || apiSessionData.Mfa == nil || apiSessionData.EndpointState == nil {
return nil
}
var ret *time.Time = nil
if p.PromptOnWake && apiSessionData.EndpointState.WokenAt != nil {
ret = apiSessionData.EndpointState.WokenAt
}
if p.PromptOnUnlock && apiSessionData.EndpointState.UnlockedAt != nil {
if ret == nil || apiSessionData.EndpointState.UnlockedAt.After(*ret) {
ret = apiSessionData.EndpointState.UnlockedAt
}
}
return ret
}
func (p *PostureCheckMfa) IsLegacyClient(apiSessionData *ApiSessionPostureData) bool {
if apiSessionData.SdkInfo == nil {
return true // don't know what it is
@@ -154,7 +177,7 @@ func (p *PostureCheckMfa) FailureValues(apiSessionId string, pd *PostureData) Po
}
ret.Criteria.TimeoutSeconds = p.GetTimeoutSeconds()
if apiSessionData, ok := pd.ApiSessions[apiSessionId]; ok {
if apiSessionData.Mfa != nil {
ret.ActualValue.TimedOutSeconds = apiSessionData.Mfa.TimedOut
+6 -1
View File
@@ -24,6 +24,7 @@ import (
"github.com/openziti/foundation/util/errorz"
"go.etcd.io/bbolt"
"strings"
"time"
)
var _ PostureCheckSubType = &PostureCheckOperatingSystem{}
@@ -32,6 +33,10 @@ type PostureCheckOperatingSystem struct {
OperatingSystems []OperatingSystem
}
func (p *PostureCheckOperatingSystem) LastUpdatedAt(id string, pd *PostureData) *time.Time {
return nil
}
func (p *PostureCheckOperatingSystem) GetTimeoutRemainingSeconds(_ string, _ *PostureData) int64 {
return PostureCheckNoTimeout
}
@@ -42,7 +47,7 @@ func (p *PostureCheckOperatingSystem) GetTimeoutSeconds() int64 {
func (p *PostureCheckOperatingSystem) FailureValues(_ string, pd *PostureData) PostureCheckFailureValues {
return &PostureCheckFailureValuesOperatingSystem{
ActualValue: pd.Os,
ActualValue: pd.Os,
ExpectedValue: p.OperatingSystems,
}
}
@@ -21,6 +21,7 @@ import (
"github.com/openziti/edge/controller/persistence"
"go.etcd.io/bbolt"
"strings"
"time"
)
var _ PostureCheckSubType = &PostureCheckProcess{}
@@ -33,6 +34,10 @@ type PostureCheckProcess struct {
Fingerprint string
}
func (p *PostureCheckProcess) LastUpdatedAt(id string, pd *PostureData) *time.Time {
return nil
}
func (p *PostureCheckProcess) GetTimeoutSeconds() int64 {
return PostureCheckNoTimeout
}
@@ -159,4 +164,4 @@ func (p PostureCheckFailureValuesProcess) Expected() interface{} {
func (p PostureCheckFailureValuesProcess) Actual() interface{} {
return p.ActualValue
}
}
@@ -22,6 +22,7 @@ import (
"github.com/michaelquigley/pfxlog"
"github.com/openziti/edge/controller/persistence"
"go.etcd.io/bbolt"
"time"
)
var _ PostureCheckSubType = &PostureCheckProcessMulti{}
@@ -32,6 +33,10 @@ type PostureCheckProcessMulti struct {
Processes []*ProcessMulti
}
func (p *PostureCheckProcessMulti) LastUpdatedAt(id string, pd *PostureData) *time.Time {
return nil
}
func (p *PostureCheckProcessMulti) GetTimeoutSeconds() int64 {
return PostureCheckNoTimeout
}
@@ -21,6 +21,7 @@ import (
"github.com/openziti/edge/controller/persistence"
"go.etcd.io/bbolt"
"strings"
"time"
)
var _ PostureCheckSubType = &PostureCheckDomains{}
@@ -29,6 +30,10 @@ type PostureCheckDomains struct {
Domains []string
}
func (p *PostureCheckDomains) LastUpdatedAt(id string, pd *PostureData) *time.Time {
return nil
}
func (p *PostureCheckDomains) GetTimeoutSeconds() int64 {
return PostureCheckNoTimeout
}
@@ -24,7 +24,7 @@ const (
type PostureResponseMfa struct {
*PostureResponse
ApiSessionId string `json:"-"`
ApiSessionId string `json:"-"`
PassedMfaAt *time.Time `json:"passedMfaAt"`
}
+4 -4
View File
@@ -4293,10 +4293,10 @@ func init() {
"type": "object",
"required": [
"meta",
"error"
"data"
],
"properties": {
"error": {
"data": {
"$ref": "#/definitions/detailMfa"
},
"meta": {
@@ -10006,10 +10006,10 @@ func init() {
"type": "object",
"required": [
"meta",
"error"
"data"
],
"properties": {
"error": {
"data": {
"$ref": "#/definitions/detailMfa"
},
"meta": {
+4 -4
View File
@@ -16445,10 +16445,10 @@ func init() {
"type": "object",
"required": [
"meta",
"error"
"data"
],
"properties": {
"error": {
"data": {
"$ref": "#/definitions/detailMfa"
},
"meta": {
@@ -37024,10 +37024,10 @@ func init() {
"type": "object",
"required": [
"meta",
"error"
"data"
],
"properties": {
"error": {
"data": {
"$ref": "#/definitions/detailMfa"
},
"meta": {
+15 -15
View File
@@ -43,9 +43,9 @@ import (
// swagger:model detailMfaEnvelope
type DetailMfaEnvelope struct {
// error
// data
// Required: true
Error *DetailMfa `json:"error"`
Data *DetailMfa `json:"data"`
// meta
// Required: true
@@ -56,7 +56,7 @@ type DetailMfaEnvelope struct {
func (m *DetailMfaEnvelope) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateError(formats); err != nil {
if err := m.validateData(formats); err != nil {
res = append(res, err)
}
@@ -70,18 +70,18 @@ func (m *DetailMfaEnvelope) Validate(formats strfmt.Registry) error {
return nil
}
func (m *DetailMfaEnvelope) validateError(formats strfmt.Registry) error {
func (m *DetailMfaEnvelope) validateData(formats strfmt.Registry) error {
if err := validate.Required("error", "body", m.Error); err != nil {
if err := validate.Required("data", "body", m.Data); err != nil {
return err
}
if m.Error != nil {
if err := m.Error.Validate(formats); err != nil {
if m.Data != nil {
if err := m.Data.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("error")
return ve.ValidateName("data")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("error")
return ce.ValidateName("data")
}
return err
}
@@ -114,7 +114,7 @@ func (m *DetailMfaEnvelope) validateMeta(formats strfmt.Registry) error {
func (m *DetailMfaEnvelope) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateError(ctx, formats); err != nil {
if err := m.contextValidateData(ctx, formats); err != nil {
res = append(res, err)
}
@@ -128,14 +128,14 @@ func (m *DetailMfaEnvelope) ContextValidate(ctx context.Context, formats strfmt.
return nil
}
func (m *DetailMfaEnvelope) contextValidateError(ctx context.Context, formats strfmt.Registry) error {
func (m *DetailMfaEnvelope) contextValidateData(ctx context.Context, formats strfmt.Registry) error {
if m.Error != nil {
if err := m.Error.ContextValidate(ctx, formats); err != nil {
if m.Data != nil {
if err := m.Data.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("error")
return ve.ValidateName("data")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("error")
return ce.ValidateName("data")
}
return err
}
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type DialBind string
func NewDialBind(value DialBind) *DialBind {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated DialBind.
func (m DialBind) Pointer() *DialBind {
return &m
}
const (
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type IdentityType string
func NewIdentityType(value IdentityType) *IdentityType {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated IdentityType.
func (m IdentityType) Pointer() *IdentityType {
return &m
}
const (
+5
View File
@@ -53,6 +53,11 @@ func (m Links) Validate(formats strfmt.Registry) error {
}
if val, ok := m[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k)
}
return err
}
}
+5
View File
@@ -53,6 +53,11 @@ func (m ListProtocols) Validate(formats strfmt.Registry) error {
}
if val, ok := m[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k)
}
return err
}
}
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type MfaFormats string
func NewMfaFormats(value MfaFormats) *MfaFormats {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated MfaFormats.
func (m MfaFormats) Pointer() *MfaFormats {
return &m
}
const (
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type MfaProviders string
func NewMfaProviders(value MfaProviders) *MfaProviders {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated MfaProviders.
func (m MfaProviders) Pointer() *MfaProviders {
return &m
}
const (
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type OsType string
func NewOsType(value OsType) *OsType {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated OsType.
func (m OsType) Pointer() *OsType {
return &m
}
const (
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type PostureCheckType string
func NewPostureCheckType(value PostureCheckType) *PostureCheckType {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated PostureCheckType.
func (m PostureCheckType) Pointer() *PostureCheckType {
return &m
}
const (
+5
View File
@@ -108,6 +108,11 @@ func (m *PostureData) validateAPISessionPostureData(formats strfmt.Registry) err
}
if val, ok := m.APISessionPostureData[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("apiSessionPostureData" + "." + k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("apiSessionPostureData" + "." + k)
}
return err
}
}
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type Semantic string
func NewSemantic(value Semantic) *Semantic {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated Semantic.
func (m Semantic) Pointer() *Semantic {
return &m
}
const (
+5
View File
@@ -53,6 +53,11 @@ func (m TerminatorCostMap) Validate(formats strfmt.Registry) error {
}
if val, ok := m[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k)
}
return err
}
}
+6 -2
View File
@@ -44,8 +44,12 @@ import (
type TerminatorPrecedence string
func NewTerminatorPrecedence(value TerminatorPrecedence) *TerminatorPrecedence {
v := value
return &v
return &value
}
// Pointer returns a pointer to a freshly-allocated TerminatorPrecedence.
func (m TerminatorPrecedence) Pointer() *TerminatorPrecedence {
return &m
}
const (
+5
View File
@@ -49,6 +49,11 @@ func (m TerminatorPrecedenceMap) Validate(formats strfmt.Registry) error {
if val, ok := m[k]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(k)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName(k)
}
return err
}
}
+5
View File
@@ -91,6 +91,11 @@ func (m *Version) validateAPIVersions(formats strfmt.Registry) error {
}
if val, ok := m.APIVersions[k][kk]; ok {
if err := val.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("apiVersions" + "." + k + "." + kk)
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("apiVersions" + "." + k + "." + kk)
}
return err
}
}
+2 -2
View File
@@ -3128,9 +3128,9 @@ definitions:
type: object
required:
- meta
- error
- data
properties:
error:
data:
$ref: '#/definitions/detailMfa'
meta:
$ref: '#/definitions/meta'
+2 -2
View File
@@ -11870,9 +11870,9 @@ definitions:
type: object
required:
- meta
- error
- data
properties:
error:
data:
$ref: '#/definitions/detailMfa'
meta:
$ref: '#/definitions/meta'
+2 -2
View File
@@ -228,11 +228,11 @@ definitions:
type: object
required:
- meta
- error
- data
properties:
meta:
$ref: 'standard-responses.yml#/definitions/meta'
error:
data:
$ref: '#/definitions/detailMfa'
detailMfa:
type: object
+2 -3
View File
@@ -20,14 +20,13 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/Jeffail/gabs"
"github.com/michaelquigley/pfxlog"
"github.com/openziti/foundation/util/errorz"
"github.com/openziti/foundation/util/stringz"
"net/http"
"reflect"
"strings"
"github.com/Jeffail/gabs"
"github.com/michaelquigley/pfxlog"
)
func (ctx *TestContext) setJsonValue(container *gabs.Container, value interface{}, path ...string) {
+241 -119
View File
@@ -20,9 +20,7 @@
package tests
import (
"encoding/json"
"fmt"
"github.com/Jeffail/gabs"
"github.com/google/uuid"
"github.com/openziti/edge/eid"
"github.com/openziti/edge/rest_model"
@@ -72,11 +70,21 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().SetBody(postureCheckJson).Post("/posture-checks")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
postureCheckId := ctx.getEntityId(resp.Body())
ctx.Req.NotEmpty(postureCheckId)
resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().Get("/posture-checks/" + postureCheckId)
ctx.Req.NoError(err)
responseEnvelope := rest_model.DetailPostureCheckEnvelope{}
err = responseEnvelope.UnmarshalJSON(resp.Body())
ctx.Req.NoError(err)
postureCheckDetail := responseEnvelope.Data().(*rest_model.PostureCheckMfaDetail)
ctx.AdminManagementSession.requireNewServicePolicyWithSemantic("Dial", "AllOf", s("#"+serviceRole), s("#"+identityRole), s("#"+postureCheckRole))
ctx.AdminManagementSession.requireNewEdgeRouterPolicy(s("#all"), s("#"+identityRole))
@@ -94,25 +102,36 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err := serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
querySet := serviceEnvelope.Data.PostureQueries
ctx.Req.NotNil(querySet)
ctx.Req.NotEmpty(querySet)
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
postureQueries := querySet[0].PostureQueries
ctx.Req.NoError(err)
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query is currently failing", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.False(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.False(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Equal(-1, int(postureQueries[0].Path("timeout").Data().(float64)))
ctx.Req.False(*querySet[0].IsPassing)
ctx.Req.False(*postureQueries[0].IsPassing)
ctx.Req.Equal(int64(-1), *postureQueries[0].Timeout)
})
t.Run("updatedAt equals posture check createdAt", func(t *testing.T) {
//fix this
ctx.testContextChanged(t)
ctx.Req.NotNil(postureCheckDetail)
ctx.Req.NotEmpty(postureCheckDetail.CreatedAt())
postureCheckDetail.CreatedAt().Equal(*postureQueries[0].CreatedAt)
})
})
@@ -130,7 +149,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
listEnvelop := rest_model.FailedServiceRequestEnvelope{}
ctx.Req.NoError(json.Unmarshal(resp.Body(), &listEnvelop))
ctx.Req.NoError(listEnvelop.UnmarshalBinary(resp.Body()))
ctx.Req.NotEmpty(listEnvelop.Data)
})
@@ -147,7 +166,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Post("/current-identity/mfa")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
t.Run("does not allow service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -161,16 +180,20 @@ func Test_PostureChecks_MFA(t *testing.T) {
t.Run("by finishing enrollment in MFA", func(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Get("/current-identity/mfa")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
standardJsonResponseTests(resp, http.StatusOK, t)
mfaEnvelope := &rest_model.DetailMfaEnvelope{}
mfa, err := gabs.ParseJSON(resp.Body())
err = mfaEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(mfaEnvelope)
ctx.Req.NotNil(mfaEnvelope.Data)
rawUrl := mfa.Path("data.provisioningUrl").Data().(string)
ctx.Req.NotEmpty(rawUrl)
mfa := mfaEnvelope.Data
ctx.Req.NotNil(mfa.ID)
ctx.Req.NotEmpty(mfa.ProvisioningURL)
parsedUrl, err := url.Parse(rawUrl)
parsedUrl, err := url.Parse(mfa.ProvisioningURL)
ctx.Req.NoError(err)
queryParams, err := url.ParseQuery(parsedUrl.RawQuery)
@@ -190,7 +213,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
Post("/current-identity/mfa/verify")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
t.Run("allows service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -204,25 +227,34 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err = serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
entityService := serviceEnvelope.Data
querySet := entityService.PostureQueries
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
ctx.Req.NoError(err)
postureQueries := querySet[0].PostureQueries
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query is currently passing", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.True(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Equal(-1, int(postureQueries[0].Path("timeout").Data().(float64)))
ctx.Req.True(*querySet[0].IsPassing)
ctx.Req.True(*postureQueries[0].IsPassing)
ctx.Req.Equal(int64(-1), *postureQueries[0].Timeout)
})
t.Run("updatedAt equals posture check createdAt", func(t *testing.T) {
//fix this
ctx.testContextChanged(t)
ctx.Req.NotNil(postureCheckDetail)
ctx.Req.NotEmpty(postureCheckDetail.CreatedAt())
postureCheckDetail.CreatedAt().Equal(*postureQueries[0].CreatedAt)
})
})
})
@@ -242,12 +274,13 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
sessionContainer, err := gabs.ParseJSON(resp.Body())
sessionEnvelope := &rest_model.SessionCreateEnvelope{}
err = sessionEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.True(sessionContainer.ExistsP("data.id"))
sessionId, ok := sessionContainer.Path("data.id").Data().(string)
ctx.Req.True(ok)
ctx.Req.NotNil(sessionEnvelope.Data.ID)
sessionId := *sessionEnvelope.Data.ID
ctx.Req.NotEmpty(sessionId)
t.Run("removing MFA while the service requires MFA", func(t *testing.T) {
@@ -317,10 +350,20 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp := ctx.AdminManagementSession.createEntityOfType("posture-checks", postureCheckBody)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
postureCheckId := ctx.getEntityId(resp.Body())
ctx.Req.NotEmpty(postureCheckId)
resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().Get("/posture-checks/" + postureCheckId)
ctx.Req.NoError(err)
responseEnvelope := rest_model.DetailPostureCheckEnvelope{}
err = responseEnvelope.UnmarshalJSON(resp.Body())
ctx.Req.NoError(err)
postureCheckDetail := responseEnvelope.Data().(*rest_model.PostureCheckMfaDetail)
t.Run("identity can see service via policies", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(enrolledIdentitySession.isServiceVisibleToUser(service.Id))
@@ -330,25 +373,37 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err = serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
entityService := serviceEnvelope.Data
ctx.Req.NotNil(entityService)
ctx.Req.NotNil(entityService.ID)
querySet := entityService.PostureQueries
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
ctx.Req.NoError(err)
postureQueries := querySet[0].PostureQueries
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query is currently failing", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.False(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.False(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Equal(0, int(postureQueries[0].Path("timeoutRemaining").Data().(float64)))
ctx.Req.False(*querySet[0].IsPassing)
ctx.Req.False(*postureQueries[0].IsPassing)
ctx.Req.Equal(int64(0), *postureQueries[0].TimeoutRemaining)
})
t.Run("updatedAt equals posture check createdAt", func(t *testing.T) {
//fix this
ctx.testContextChanged(t)
ctx.Req.NotNil(postureCheckDetail)
ctx.Req.NotEmpty(postureCheckDetail.CreatedAt())
postureCheckDetail.CreatedAt().Equal(*postureQueries[0].CreatedAt)
})
})
@@ -365,9 +420,8 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().Get("/identities/" + enrolledIdentitySession.identityId + "/failed-service-requests")
ctx.Req.NoError(err)
listEnvelop := rest_model.FailedServiceRequestEnvelope{}
ctx.Req.NoError(json.Unmarshal(resp.Body(), &listEnvelop))
listEnvelop := &rest_model.FailedServiceRequestEnvelope{}
ctx.Req.NoError(listEnvelop.UnmarshalBinary(resp.Body()))
ctx.Req.NotEmpty(listEnvelop.Data)
})
})
@@ -383,7 +437,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Post("/current-identity/mfa")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
t.Run("does not allow service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -397,16 +451,19 @@ func Test_PostureChecks_MFA(t *testing.T) {
t.Run("by finishing enrollment in MFA", func(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Get("/current-identity/mfa")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
standardJsonResponseTests(resp, http.StatusOK, t)
mfa, err := gabs.ParseJSON(resp.Body())
mfaEnvelope := &rest_model.DetailMfaEnvelope{}
err = mfaEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(mfaEnvelope)
ctx.Req.NotNil(mfaEnvelope.Data)
rawUrl := mfa.Path("data.provisioningUrl").Data().(string)
ctx.Req.NotEmpty(rawUrl)
mfa := mfaEnvelope.Data
ctx.Req.NotNil(mfa.ID)
ctx.Req.NotEmpty(mfa.ProvisioningURL)
parsedUrl, err := url.Parse(rawUrl)
parsedUrl, err := url.Parse(mfa.ProvisioningURL)
ctx.Req.NoError(err)
queryParams, err := url.ParseQuery(parsedUrl.RawQuery)
@@ -426,7 +483,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
Post("/current-identity/mfa/verify")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
t.Run("allows service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -440,25 +497,28 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err := serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
querySet := serviceEnvelope.Data.PostureQueries
ctx.Req.NotNil(querySet)
ctx.Req.NotEmpty(querySet)
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
postureQueries := querySet[0].PostureQueries
ctx.Req.NoError(err)
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query is currently passing", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.True(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Greater(int(postureQueries[0].Path("timeout").Data().(float64)), 0)
ctx.Req.True(*querySet[0].IsPassing)
ctx.Req.True(*postureQueries[0].IsPassing)
ctx.Req.Greater(*postureQueries[0].Timeout, int64(0))
})
})
@@ -473,7 +533,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := enrolledIdentitySession.NewRequest().SetBody(wokeState).Post("posture-response")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
t.Run("woke posture response should include service timeout change event", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -496,26 +556,71 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err := serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
querySet := serviceEnvelope.Data.PostureQueries
ctx.Req.NotNil(querySet)
ctx.Req.NotEmpty(querySet)
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
postureQueries := querySet[0].PostureQueries
ctx.Req.NoError(err)
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query has a lower timeout", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.True(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Greater(int(postureQueries[0].Path("timeoutRemaining").Data().(float64)), 0)
ctx.Req.LessOrEqual(int(postureQueries[0].Path("timeoutRemaining").Data().(float64)), 300)
ctx.Req.True(*querySet[0].IsPassing)
ctx.Req.True(*postureQueries[0].IsPassing)
ctx.Req.Greater(*postureQueries[0].TimeoutRemaining, int64(0))
ctx.Req.LessOrEqual(*postureQueries[0].TimeoutRemaining, int64(300))
})
t.Run("query has a new updatedAt value", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(time.Time(*postureQueries[0].UpdatedAt).After(time.Time(*postureCheckDetail.UpdatedAt())), "posture query updated at [%s] should now be after original time [%s]", postureQueries[0].UpdatedAt.String(), postureCheckDetail.UpdatedAt().String())
})
t.Run("updating the posture check further advances updatedAt", func(t *testing.T) {
ctx.testContextChanged(t)
newTimeout := int64(600)
mfaPatch := &rest_model.PostureCheckMfaPatch{}
mfaPatch.TimeoutSeconds = &newTimeout
body, err := mfaPatch.MarshalJSON()
ctx.Req.NoError(err)
resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().SetBody(body).Patch("/posture-checks/" + postureCheckId)
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
resp, err = enrolledIdentitySession.newAuthenticatedRequest().Get("/services/" + service.Id)
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
patchedServiceEnv := &rest_model.DetailServiceEnvelope{}
err = patchedServiceEnv.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
patchedQuerySet := patchedServiceEnv.Data.PostureQueries
ctx.Req.NotNil(patchedQuerySet)
ctx.Req.NotEmpty(patchedQuerySet)
ctx.Req.Len(patchedQuerySet, 1)
patchedPostureQueries := patchedQuerySet[0].PostureQueries
ctx.Req.NoError(err)
ctx.Req.Len(patchedPostureQueries, 1)
ctx.Req.Equal(postureCheckId, *patchedPostureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *patchedPostureQueries[0].QueryType)
ctx.Req.True(time.Time(*patchedPostureQueries[0].UpdatedAt).After(time.Time(*postureQueries[0].UpdatedAt)), "posture query updated at [%s] should now be after state change time [%s]", patchedPostureQueries[0].UpdatedAt.String(), postureCheckDetail.UpdatedAt().String())
})
})
})
@@ -536,12 +641,15 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
sessionContainer, err := gabs.ParseJSON(resp.Body())
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err = serviceEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.True(sessionContainer.ExistsP("data.id"))
sessionId, ok := sessionContainer.Path("data.id").Data().(string)
ctx.Req.True(ok)
entityService := serviceEnvelope.Data
ctx.Req.NotNil(entityService)
ctx.Req.NotNil(entityService.ID)
sessionId := *entityService.ID
ctx.Req.NotEmpty(sessionId)
})
@@ -640,7 +748,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp := ctx.AdminManagementSession.createEntityOfType("posture-checks", postureCheckBody)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
postureCheckId := ctx.getEntityId(resp.Body())
ctx.Req.NotEmpty(postureCheckId)
@@ -663,7 +771,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Post("/current-identity/mfa")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
t.Run("does not allow service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -677,16 +785,20 @@ func Test_PostureChecks_MFA(t *testing.T) {
t.Run("by finishing enrollment in MFA", func(t *testing.T) {
resp, err := enrolledIdentitySession.newAuthenticatedRequest().Get("/current-identity/mfa")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
standardJsonResponseTests(resp, http.StatusOK, t)
mfaEnvelope := &rest_model.DetailMfaEnvelope{}
mfa, err := gabs.ParseJSON(resp.Body())
err = mfaEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(mfaEnvelope)
ctx.Req.NotNil(mfaEnvelope.Data)
rawUrl := mfa.Path("data.provisioningUrl").Data().(string)
ctx.Req.NotEmpty(rawUrl)
mfa := mfaEnvelope.Data
ctx.Req.NotNil(mfa.ID)
ctx.Req.NotEmpty(mfa.ProvisioningURL)
parsedUrl, err := url.Parse(rawUrl)
parsedUrl, err := url.Parse(mfa.ProvisioningURL)
ctx.Req.NoError(err)
queryParams, err := url.ParseQuery(parsedUrl.RawQuery)
@@ -706,7 +818,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
Post("/current-identity/mfa/verify")
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
t.Run("allows service session creation", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -720,25 +832,28 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.testContextChanged(t)
code, body := enrolledIdentitySession.query("/services/" + service.Id)
ctx.Req.Equal(http.StatusOK, code)
entityService, err := gabs.ParseJSON(body)
serviceEnvelope := &rest_model.DetailServiceEnvelope{}
err := serviceEnvelope.UnmarshalBinary(body)
ctx.Req.NoError(err)
querySet, err := entityService.Path("data.postureQueries").Children()
ctx.Req.NoError(err)
querySet := serviceEnvelope.Data.PostureQueries
ctx.Req.NotNil(querySet)
ctx.Req.NotEmpty(querySet)
ctx.Req.Len(querySet, 1)
postureQueries, err := querySet[0].Path("postureQueries").Children()
postureQueries := querySet[0].PostureQueries
ctx.Req.NoError(err)
ctx.Req.Len(postureQueries, 1)
ctx.Req.Equal(postureCheckId, postureQueries[0].Path("id").Data().(string))
ctx.Req.Equal(string(postureCheck.TypeID()), postureQueries[0].Path("queryType").Data().(string))
ctx.Req.Equal(postureCheckId, *postureQueries[0].ID)
ctx.Req.Equal(postureCheck.TypeID(), *postureQueries[0].QueryType)
t.Run("query is currently passing", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.Req.True(querySet[0].Path("isPassing").Data().(bool))
ctx.Req.True(postureQueries[0].Path("isPassing").Data().(bool))
ctx.Req.Greater(int(postureQueries[0].Path("timeout").Data().(float64)), 0)
ctx.Req.True(*querySet[0].IsPassing)
ctx.Req.True(*postureQueries[0].IsPassing)
ctx.Req.Greater(*postureQueries[0].Timeout, int64(0))
})
})
})
@@ -759,30 +874,37 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
sessionContainer, err := gabs.ParseJSON(resp.Body())
sessionCreateEnvelope := &rest_model.SessionCreateEnvelope{}
err = sessionCreateEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(sessionCreateEnvelope.Data)
ctx.Req.NotNil(sessionCreateEnvelope.Data.ID)
ctx.Req.True(sessionContainer.ExistsP("data.id"))
sessionId, ok := sessionContainer.Path("data.id").Data().(string)
ctx.Req.True(ok)
sessionId := *sessionCreateEnvelope.Data.ID
ctx.Req.NotEmpty(sessionId)
resp, err = ctx.AdminManagementSession.NewRequest().Get("/sessions/" + sessionId)
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
ctx.Req.NoError(err)
sessionDetailEnvelope := &rest_model.DetailSessionEnvelope{}
err = sessionDetailEnvelope.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(sessionDetailEnvelope.Data)
ctx.Req.NotNil(sessionDetailEnvelope.Data.ID)
resp, err = newSession.NewRequest().Get("/current-api-session/service-updates")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
serviceUpdateContainer, err := gabs.ParseJSON(resp.Body())
serviceUpdatesEnvelop := &rest_model.ListCurrentAPISessionServiceUpdatesEnvelope{}
err = serviceUpdatesEnvelop.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(serviceUpdatesEnvelop.Data)
ctx.Req.NotNil(serviceUpdatesEnvelop.Data.LastChangeAt)
ctx.Req.False(time.Time(*serviceUpdatesEnvelop.Data.LastChangeAt).IsZero())
ctx.Req.True(serviceUpdateContainer.ExistsP("data.lastChangeAt"))
lastChangeAt, ok := serviceUpdateContainer.Path("data.lastChangeAt").Data().(string)
ctx.Req.True(ok)
ctx.Req.NotEmpty(lastChangeAt)
originalLastChangedAt := *serviceUpdatesEnvelop.Data.LastChangeAt
t.Run("after the MFA posture check timeout", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -799,16 +921,16 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
serviceUpdateContainer, err := gabs.ParseJSON(resp.Body())
serviceUpdatesEnvelop := &rest_model.ListCurrentAPISessionServiceUpdatesEnvelope{}
err = serviceUpdatesEnvelop.UnmarshalBinary(resp.Body())
ctx.Req.NoError(err)
ctx.Req.NotNil(serviceUpdatesEnvelop.Data)
ctx.Req.NotNil(serviceUpdatesEnvelop.Data.LastChangeAt)
ctx.Req.False(time.Time(*serviceUpdatesEnvelop.Data.LastChangeAt).IsZero())
ctx.Req.True(serviceUpdateContainer.ExistsP("data.lastChangeAt"))
newLastChangeAt := *serviceUpdatesEnvelop.Data.LastChangeAt
newLastChangeAt, ok := serviceUpdateContainer.Path("data.lastChangeAt").Data().(string)
ctx.Req.True(ok)
ctx.Req.NotEmpty(newLastChangeAt)
ctx.Req.NotEqual(newLastChangeAt, lastChangeAt)
ctx.Req.False(originalLastChangedAt.Equal(newLastChangeAt))
})
t.Run("the existing session was removed", func(t *testing.T) {
@@ -860,7 +982,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp := ctx.AdminManagementSession.createEntityOfType("posture-checks", postureCheckBody)
standardJsonResponseTests(resp, http.StatusCreated, t)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
id := ctx.getEntityId(resp.Body())
ctx.Req.NotEmpty(id)
@@ -870,7 +992,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := ctx.AdminManagementSession.NewRequest().Get("posture-checks/" + id)
ctx.Req.NoError(err)
ctx.Req.NotNil(resp)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
envelope := rest_model.DetailPostureCheckEnvelope{}
@@ -915,7 +1037,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
ctx.Req.NoError(err)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
t.Run("can be retrieved", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -923,7 +1045,7 @@ func Test_PostureChecks_MFA(t *testing.T) {
resp, err := ctx.AdminManagementSession.NewRequest().Get("posture-checks/" + id)
ctx.Req.NoError(err)
ctx.Req.NotNil(resp)
standardJsonResponseTests(resp, http.StatusOK, t)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
envelope := rest_model.DetailPostureCheckEnvelope{}