Kotlin Mockk a getter with parameters - spring

My code is extending Spring Boot's Authentication class with properties derived from the JWT. For example:
import org.springframework.security.core.Authentication
...
val Authentication.role: List<String>?
get() = (principal as? Jwt)?.let {
if (it.containsClaim("test/role/claim")) {
it.getClaimAsStringList("test/role/claim")
} else {
null
}
}
This works in the code just fine but I'm stuck on how to test it with mockk.
In this example, "role" won't get hit at all
fun mockAuthenticationWithAuthorities(
userId: String,
authorities: Collection<Authorities> = emptyList(),
principal: Any? = null,
role: List<String>? = null,
) =
mockk<Authentication>().also {
every { it.name } returns userId
every { it.authorities } returns authorities.map { SimpleGrantedAuthority(it.value) }
every { it.principal } returns principal
every { it.role } returns role
}
Based on some of the answers here I tried this variation:
fun mockAuthenticationWithAuthorities(
userId: String,
authorities: Collection<Authorities> = emptyList(),
principal: Any? = null,
role: List<String>? = null,
) =
mockk<Authentication>().also {
every { it.name } returns userId
every { it.authorities } returns authorities.map { SimpleGrantedAuthority(it.value) }
every { it.principal } returns principal
every { it getProperty "role" } returns role
}
But it fails with io.mockk.MockKException: can't find property role for dynamic property get
Any ideas how to properly test this case?
Thanks.

Maybe duplicated.
In your case, to mock extension function you should use mockkStatic:
mockkStatic("org.springframework.security.core.Authentication.YourFileKt")
mockk<Authentication> {
every { role } returns role
}
ps.: you don't need to use also for mockk, just call with {}:
mockk<SomeType> {
// any `every` declaration
}

Related

TypeGraphQL - Not able to match all the interfaces of a union

Summary
The goal is to declare the return type of a mutation using a union in order to express multiple states: Success and user errors
Being able to select concrete types according to the use cases:
mutation($data: CreateUserInput!) {
createUser(data: $data){
... on CreateUserSuccess {
user {
id
}
}
... on EmailTakenError {
emailWasTaken
}
... on UserError {
code
message
}
}
}
Implementation using TypeGraphQ:
#ObjectType()
class CreateUserSuccess {
#Field(() => User)
user: User
}
#ObjectType()
class EmailTakenError {
#Field()
emailWasTaken: boolean
}
const mapMutationValueKeyToObjectType = {
user: CreateUserSuccess,
code: UserError,
emailWasTaken: EmailTakenError
}
const CreateUserPayload = createUnionType({
name: 'CreateUserPayload',
types: () => [CreateUserSuccess, EmailTakenError, UserError] as const,
resolveType: mutationValue => {
const mapperKeys = Object.keys(mapMutationValueKeyToObjectType)
const mutationValueKey = mapperKeys.find((key) => key in mutationValue)
return mapMutationValueKeyToObjectType[mutationValueKey]
}
})
#InputType()
class CreateUserInput implements Partial<User> {
#Field()
name: string
#Field()
email: string
}
#Resolver(User)
export class UserResolver {
#Mutation(() => CreateUserPayload)
createUser (#Arg('data', {
description: 'Represents the input data needed to create a new user'
}) createUserInput: CreateUserInput) {
const { name, email } = createUserInput
return createUser({ name, email })
}
}
Data layer
export const createUser = async ({
name, email
}: { name: string; email: string; }) => {
const existingUser = await dbClient.user.findUnique({
where: {
email
}
})
if (existingUser) {
return {
code: ErrorCode.DUPLICATE_ENTRY,
message: "There's an existing user with the provided email.",
emailWasTaken: true
}
}
return dbClient.user.create({
data: {
name,
email
}
})
}
Issue
The response doesn't resolve all of the selected fields according to their unions, even by returning fields that are related to different types
if (existingUser) {
return {
code: ErrorCode.DUPLICATE_ENTRY,
message: "There's an existing user with the provided email.",
emailWasTaken: true
}
}
My doubt is this case is, why emailWasTaken is not being returned within the response if the EmailTakenError type is being selected?
This was an interpretation mistake on my part
The reasoning is that resolvers with a union type as the return definition should indeed just return one of those, in the case above, UserError and EmailTakenError wouldn't be returned on the same response
More info on this GitHub discussion

Supabase third party oAuth providers are returning null?

I'm trying to implement Facebook, Google and Twitter authentication. So far, I've set up the apps within the respective developer platforms, added those keys/secrets to my Supabase console, and created this graphql resolver:
/* eslint-disable #typescript-eslint/explicit-module-boundary-types */
import camelcaseKeys from 'camelcase-keys';
import { supabase } from 'lib/supabaseClient';
import { LoginInput, Provider } from 'generated/types';
import { Provider as SupabaseProvider } from '#supabase/supabase-js';
import Context from '../../context';
import { User } from '#supabase/supabase-js';
export default async function login(
_: any,
{ input }: { input: LoginInput },
{ res, req }: Context
): Promise<any> {
const { provider } = input;
// base level error object
const errorObject = {
__typename: 'AuthError',
};
// return error object if no provider is given
if (!provider) {
return {
...errorObject,
message: 'Must include provider',
};
}
try {
const { user, session, error } = await supabase.auth.signIn({
// provider can be 'github', 'google', 'gitlab', or 'bitbucket'
provider: 'facebook',
});
console.log({ user });
console.log({ session });
console.log({ error });
if (error) {
return {
...errorObject,
message: error.message,
};
}
const response = camelcaseKeys(user as User, { deep: true });
return {
__typename: 'LoginSuccess',
accessToken: session?.access_token,
refreshToken: session?.refresh_token,
...response,
};
} catch (error) {
return {
...errorObject,
message: error.message,
};
}
}
I have three console logs set up directly underneath the signIn() function, all of which are returning null.
I can also go directly to https://<your-ref>.supabase.co/auth/v1/authorize?provider=<provider> and auth works correctly, so it appears to have been narrowed down specifically to the signIn() function. What would cause the response to return null values?
This is happening because these values are not populated until after the redirect from the OAuth server takes place. If you look at the internal code of supabase/gotrue-js you'll see null being returned explicitly.
private _handleProviderSignIn(
provider: Provider,
options: {
redirectTo?: string
scopes?: string
} = {}
) {
const url: string = this.api.getUrlForProvider(provider, {
redirectTo: options.redirectTo,
scopes: options.scopes,
})
try {
// try to open on the browser
if (isBrowser()) {
window.location.href = url
}
return { provider, url, data: null, session: null, user: null, error: null }
} catch (error) {
// fallback to returning the URL
if (!!url) return { provider, url, data: null, session: null, user: null, error: null }
return { data: null, user: null, session: null, error }
}
}
The flow is something like this:
Call `supabase.auth.signIn({ provider: 'github' })
User is sent to Github.com where they will be prompted to allow/deny your app access to their data
If they allow your app access, Github.com redirects back to your app
Now, through some Supabase magic, you will have access to the session, user, etc. data

Graphql directives doesn't work for mutation input arguments when pass the arguments as external variables

I am implementing custom Graphql directives to validate client input. A sample code as below, I referred to the official examples here: https://www.apollographql.com/docs/apollo-server/schema/creating-directives/#enforcing-value-restrictions
const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server');
const { GraphQLScalarType, GraphQLNonNull } = require('graphql');
const typeDefs = gql`
directive #validateInput on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
type Mutation {
sampleMutation(
test1: String #validateInput
nestedInput: SampleMutationInput
): String
}
input SampleMutationInput {
test2: String #validateInput
}
`;
The implementation of the directive logic:
class ValidateInputDirective extends SchemaDirectiveVisitor {
visitInputFieldDefinition(field) {
this.wrapType(field);
}
visitFieldDefinition(field) {
this.wrapType(field);
}
visitArgumentDefinition(argument) {
console.log('visitArgumentDefinition', argument);
this.wrapType(argument);
}
wrapType(field) {
console.log('wrapType', field);
if (
field.type instanceof GraphQLNonNull &&
field.type.ofType instanceof GraphQLScalarType
) {
field.type = new GraphQLNonNull(
new ValidateInputType(field.type.ofType)
);
} else if (field.type instanceof GraphQLScalarType) {
field.type = new ValidateInputType(field.type);
} else {
throw new Error(`Not a scalar type: ${field.type}`);
}
}
}
class ValidateInputType extends GraphQLScalarType {
constructor(type) {
super({
name: 'ValidatedInput',
serialize(value) {
return value;
},
parseValue(value) {
const result = type.parseValue(value);
if (/[?!]/.test(result)) {
throw new Error('Invalid characters');
}
return result;
},
parseLiteral(ast) {
const result = type.parseLiteral(ast);
if (/[?!]/.test(result)) {
throw new Error('Invalid characters');
}
return result;
},
});
}
}
export default { validateInput: ValidateInputDirective };
It works as expected for the input field 'test2', but for the argument 'test1', it works when the String value is directly passed to the mutation, then the method "parseLiteral" is called and the validation logic applied to the input value. However, when I pass the 'test1' value as external variables (via JSON format), the directive doesn't work and the method "parserValue" never be called.
What I found so far:
"parserValue" is used when the input comes from variable JSON. "parseLiteral" is used when the input comes directly from the query/mutation.
It seems a bug in Graphql tools according to https://github.com/ardatan/graphql-tools/issues/789
I want to understand:
what's the real difference between an argument passed by variable and directly pass to mutation?
is there an alternate way to apply the directives to an argument to avoid this issue?
If this is really a bug with Graphql, does it fixed now? Which version should I use to resolve the issue?

Localstorage.setItem() doesn´t work properly

I have the following validator where I check if the usernamecontains admin in it, then I want to set the role to localStorage for later use and return isAdmin: true.
For some reason most of the times doesn´t write anything to localStorage, and then it does ocassionally which is weird.
Any idea what can be wrong?
import { FormControl } from "#angular/forms";
export class AdminValidator {
static getAdminValidator() {
return function adminValidator(control: FormControl): { [s: string]: boolean } {
// Write code here..
if (control.value.match(/^admin/)) {
localStorage.setItem('role', 'admin');
return { isAdmin: true };
}
return null;
}
}
}

Changes to params in grails only seen in controller not in views

Part of my UrlMappings looks like this:
"/$lang"(controller: "main", action: "front") {
constraints {
lang inList: ['hr', 'sl', 'si']
}
}
Because I want to set lang to 'sl' if it is 'si', I created following filter:
def filters = {
all(controller: '*', action: '*') {
before = {
if(params.lang == 'si') {
params.lang = 'sl'
}
}
}
}
Problem: params.lang inside controller gets the wanted value ('sl'), but in views, params.lang gets resolved to the original value ('si'). What would you suggest to solve this problem?
Thank you!
Try to use redirects. I did this way:
def filters = {
pages(controller: 'pages', action: 'home|services|projects|project_details|contact_us|career|about_us|downloadCaseStudy') {
before = {
if (params.lang) {
if (!(params.lang in grailsApplication.config.i18nFields.locales)) {
session."$SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME" = null
params.remove('lang')
response.sendError(404)
return
}
if (params.lang == grailsApplication.config.defaultLocale) {
RCU.getLocaleResolver(request).setLocale(request, response, new Locale(params.lang))
params.remove('lang')
chain(controller: "pages", action: params.action, model:chainModel?:[:],params: params)
return false
}
} else {
String langCode = RCU.getLocale(request).getLanguage()
if (!(langCode in grailsApplication.config.i18nFields.locales)) {
params.lang = grailsApplication.config.defaultLocale
return
} else if (langCode != grailsApplication.config.defaultLocale) {
params.lang = langCode
chain(controller: params.controller, action: params.action, model:chainModel?:[:], params: params)
}
return true
}
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
A little explanation: I build urls like /ru/about_us.
1.If lang not in list - 404.
2.if lang = grailsApplication.config.defaultLocale show instead of /en/about_us just /about_us.
3. if no lang param provided - resolve from request.

Resources