@@ -3,15 +3,17 @@ package scim
33import (
44 "fmt"
55
6+ scimErrors "github.com/elimity-com/scim/errors"
67 internal "github.com/elimity-com/scim/filter"
78 "github.com/elimity-com/scim/schema"
89 filter "github.com/scim2/filter-parser/v2"
910)
1011
11- func applyToMatching (list []interface {}, t * valueExprTarget , value interface {}, replace bool ) ([]interface {}, error ) {
12+ func applyToMatching (list []interface {}, t * valueExprTarget , value interface {}, replace bool ) ([]interface {}, bool , error ) {
1213 result := make ([]interface {}, len (list ))
1314 copy (result , list )
1415
16+ matched := false
1517 for i , elem := range result {
1618 m , ok := elem .(map [string ]interface {})
1719 if ! ok {
@@ -20,6 +22,7 @@ func applyToMatching(list []interface{}, t *valueExprTarget, value interface{},
2022 if ! matchesExpression (m , t .expr , t .attr , t .refSchema ) {
2123 continue
2224 }
25+ matched = true
2326 if t .subAttrName != "" {
2427 updated := copyMap (m )
2528 updated [t .subAttrName ] = value
@@ -49,7 +52,7 @@ func applyToMatching(list []interface{}, t *valueExprTarget, value interface{},
4952 }
5053 }
5154 }
52- return result , nil
55+ return result , matched , nil
5356}
5457
5558func copyMap (m map [string ]interface {}) map [string ]interface {} {
@@ -263,7 +266,7 @@ func applyAdd(attrs ResourceAttributes, op PatchOperation, s schema.Schema, exte
263266 if ! ok {
264267 return nil , fmt .Errorf ("expected multi-valued attribute for %s" , attrName )
265268 }
266- list , err := applyToMatching (list , t , op .Value , false )
269+ list , _ , err := applyToMatching (list , t , op .Value , false )
267270 if err != nil {
268271 return nil , err
269272 }
@@ -405,18 +408,25 @@ func applyReplace(attrs ResourceAttributes, op PatchOperation, s schema.Schema,
405408 m [t .subAttrName ] = op .Value
406409 attrs [attrName ] = m
407410 case * valueExprTarget :
411+ // RFC 7644 Section 3.5.2.3: if the target location is a multi-valued
412+ // attribute for which a value selection filter ("valuePath") has been
413+ // supplied and no record match was made, the service provider SHALL
414+ // return a 400 error with a scimType of noTarget.
408415 existing , exists := attrs [attrName ]
409416 if ! exists {
410- return attrs , nil
417+ return nil , scimErrors . ScimErrorNoTarget
411418 }
412419 list , ok := existing .([]interface {})
413420 if ! ok {
414421 return nil , fmt .Errorf ("expected multi-valued attribute for %s" , attrName )
415422 }
416- list , err := applyToMatching (list , t , op .Value , true )
423+ list , matched , err := applyToMatching (list , t , op .Value , true )
417424 if err != nil {
418425 return nil , err
419426 }
427+ if ! matched {
428+ return nil , scimErrors .ScimErrorNoTarget
429+ }
420430 attrs [attrName ] = list
421431 }
422432 return attrs , nil
0 commit comments