1
+ package io .antmedia ;
2
+
3
+ import java .util .Collection ;
4
+ import java .util .HashSet ;
5
+ import java .util .Map ;
6
+ import java .util .Set ;
7
+ import java .util .stream .Collectors ;
8
+ import org .springframework .context .annotation .Bean ;
9
+ import org .springframework .http .HttpMethod ;
10
+ import org .springframework .security .config .Customizer ;
11
+ import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
12
+ import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
13
+ import org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
14
+ import org .springframework .security .core .GrantedAuthority ;
15
+ import org .springframework .security .core .authority .SimpleGrantedAuthority ;
16
+ import org .springframework .security .core .authority .mapping .GrantedAuthoritiesMapper ;
17
+ import org .springframework .security .core .session .SessionRegistry ;
18
+ import org .springframework .security .core .session .SessionRegistryImpl ;
19
+ import org .springframework .security .oauth2 .client .oidc .userinfo .OidcUserService ;
20
+ import org .springframework .security .oauth2 .client .registration .ClientRegistration ;
21
+ import org .springframework .security .oauth2 .client .registration .ClientRegistrationRepository ;
22
+ import org .springframework .security .oauth2 .client .registration .InMemoryClientRegistrationRepository ;
23
+ import org .springframework .security .oauth2 .client .web .DefaultOAuth2AuthorizationRequestResolver ;
24
+ import org .springframework .security .oauth2 .client .web .OAuth2AuthorizationRequestResolver ;
25
+ import org .springframework .security .oauth2 .core .AuthorizationGrantType ;
26
+ import org .springframework .security .oauth2 .core .oidc .user .OidcUserAuthority ;
27
+ import org .springframework .security .oauth2 .core .user .OAuth2UserAuthority ;
28
+ import org .springframework .security .oauth2 .jwt .JwtDecoder ;
29
+ import org .springframework .security .oauth2 .jwt .NimbusJwtDecoder ;
30
+ import org .springframework .security .web .SecurityFilterChain ;
31
+ import org .springframework .security .web .authentication .session .RegisterSessionAuthenticationStrategy ;
32
+ import org .springframework .security .web .authentication .session .SessionAuthenticationStrategy ;
33
+ import org .springframework .security .web .session .HttpSessionEventPublisher ;
34
+ import org .springframework .security .web .util .matcher .AntPathRequestMatcher ;
35
+
36
+ @ EnableWebSecurity
37
+ class SecurityConfiguration {
38
+
39
+ private static final String GROUPS = "groups" ;
40
+ private static final String REALM_ACCESS_CLAIM = "realm_access" ;
41
+ private static final String ROLES_CLAIM = "roles" ;
42
+
43
+ /*
44
+ * Realm URL in this format for keycloak
45
+ * "http://localhost:8080/realms/AntMedia";
46
+ */
47
+ private String realmUrl = null ;
48
+
49
+ /*
50
+ * webapp name like: LiveApp, live
51
+ */
52
+ private String appName = null ;
53
+ private String clientId = "stream-application" ; //"stream-application";
54
+ private String role = "user" ;
55
+
56
+
57
+ @ Bean
58
+ public SecurityFilterChain resourceServerFilterChain (HttpSecurity http ) throws Exception {
59
+ http .authorizeHttpRequests (auth -> auth
60
+ // Allows preflight requests from browser for any paths under /appName/**
61
+ .requestMatchers (new AntPathRequestMatcher ("/**" , HttpMethod .OPTIONS .name ()))
62
+ .permitAll ()
63
+ // Allow access without authentication to /appName/rest/**
64
+ .requestMatchers (new AntPathRequestMatcher ("/rest/**" ))
65
+ .permitAll ()
66
+ // Require authentication for all other paths under /appName/**
67
+ .requestMatchers (new AntPathRequestMatcher ("/" + appName + "/**" ))
68
+ .hasRole (role )
69
+ // Permit access to the root URL
70
+ .requestMatchers (new AntPathRequestMatcher ("/" ))
71
+ .permitAll ()
72
+ // Authenticate any other request
73
+ .anyRequest ().authenticated ()
74
+ );
75
+
76
+ //for vod upload
77
+ http .csrf (AbstractHttpConfigurer ::disable );
78
+
79
+ // Configure the resource server to use JWT authentication
80
+ http .oauth2ResourceServer (oauth2 -> oauth2 .jwt (Customizer .withDefaults ()));
81
+
82
+ // Configure OAuth2 login
83
+ http .oauth2Login (Customizer .withDefaults ());
84
+
85
+ return http .build ();
86
+ }
87
+
88
+
89
+ @ Bean
90
+ public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak () {
91
+ return authorities -> {
92
+ Set <GrantedAuthority > mappedAuthorities = new HashSet <>();
93
+ var authority = authorities .iterator ().next ();
94
+ boolean isOidc = authority instanceof OidcUserAuthority ;
95
+
96
+ if (isOidc ) {
97
+ var oidcUserAuthority = (OidcUserAuthority ) authority ;
98
+ var userInfo = oidcUserAuthority .getUserInfo ();
99
+
100
+ // Tokens can be configured to return roles under
101
+ // Groups or REALM ACCESS hence have to check both
102
+ if (userInfo .hasClaim (REALM_ACCESS_CLAIM )) {
103
+ var realmAccess = userInfo .getClaimAsMap (REALM_ACCESS_CLAIM );
104
+ var roles = (Collection <String >) realmAccess .get (ROLES_CLAIM );
105
+ mappedAuthorities .addAll (generateAuthoritiesFromClaim (roles ));
106
+ } else if (userInfo .hasClaim (GROUPS )) {
107
+ Collection <String > roles = userInfo .getClaim (GROUPS );
108
+ mappedAuthorities .addAll (generateAuthoritiesFromClaim (roles ));
109
+ }
110
+ } else {
111
+ var oauth2UserAuthority = (OAuth2UserAuthority ) authority ;
112
+ Map <String , Object > userAttributes = oauth2UserAuthority .getAttributes ();
113
+
114
+ if (userAttributes .containsKey (REALM_ACCESS_CLAIM )) {
115
+ Map <String , Object > realmAccess = (Map <String , Object >) userAttributes .get (REALM_ACCESS_CLAIM );
116
+ Collection <String > roles = (Collection <String >) realmAccess .get (ROLES_CLAIM );
117
+ mappedAuthorities .addAll (generateAuthoritiesFromClaim (roles ));
118
+ }
119
+ }
120
+ return mappedAuthorities ;
121
+ };
122
+ }
123
+
124
+ @ Bean
125
+ public SessionRegistry sessionRegistry () {
126
+ return new SessionRegistryImpl ();
127
+ }
128
+
129
+ @ Bean
130
+ protected SessionAuthenticationStrategy sessionAuthenticationStrategy () {
131
+ return new RegisterSessionAuthenticationStrategy (sessionRegistry ());
132
+ }
133
+
134
+ @ Bean
135
+ public HttpSessionEventPublisher httpSessionEventPublisher () {
136
+ return new HttpSessionEventPublisher ();
137
+ }
138
+
139
+ Collection <GrantedAuthority > generateAuthoritiesFromClaim (Collection <String > roles ) {
140
+ return roles .stream ().map (role -> new SimpleGrantedAuthority ("ROLE_" + role )).collect (
141
+ Collectors .toList ());
142
+ }
143
+
144
+ @ Bean
145
+ public JwtDecoder jwtDecoder () {
146
+ return NimbusJwtDecoder .withJwkSetUri (realmUrl + "/protocol/openid-connect/certs" ).build ();
147
+ }
148
+
149
+ @ Bean
150
+ public ClientRegistrationRepository clientRegistrationRepository () {
151
+ return new InMemoryClientRegistrationRepository (keycloakClientRegistration ());
152
+ }
153
+
154
+ @ Bean
155
+ public OAuth2AuthorizationRequestResolver authorizationRequestResolver (ClientRegistrationRepository clientRegistrationRepository ) {
156
+ return new DefaultOAuth2AuthorizationRequestResolver (clientRegistrationRepository , "/oauth2/authorization" );
157
+ }
158
+
159
+ @ Bean
160
+ public OidcUserService oidcUserService () {
161
+ return new OidcUserService ();
162
+ }
163
+
164
+ @ Bean
165
+ public ClientRegistration keycloakClientRegistration () {
166
+ return ClientRegistration .withRegistrationId ("keycloak" )
167
+ .clientId (clientId )
168
+ .authorizationGrantType (AuthorizationGrantType .AUTHORIZATION_CODE )
169
+ .redirectUri ("{baseUrl}/login/oauth2/code/{registrationId}" )
170
+ //.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
171
+ .scope ("openid" )
172
+ .authorizationUri (realmUrl + "/protocol/openid-connect/auth" )
173
+ .tokenUri (realmUrl + "/protocol/openid-connect/token" )
174
+ .userInfoUri (realmUrl + "/protocol/openid-connect/userinfo" )
175
+ .userNameAttributeName ("preferred_username" )
176
+ .jwkSetUri (realmUrl + "/protocol/openid-connect/certs" )
177
+ .clientName ("Keycloak" )
178
+ .build ();
179
+ }
180
+
181
+
182
+ public void setRealmUrl (String realmUrl ) {
183
+ this .realmUrl = realmUrl ;
184
+ }
185
+ public void setAppName (String appName ) {
186
+ this .appName = appName ;
187
+ }
188
+ public void setClientId (String clientId ) {
189
+ this .clientId = clientId ;
190
+ }
191
+ public void setRole (String role ) {
192
+ this .role = role ;
193
+ }
194
+ }
0 commit comments