diff options
Diffstat (limited to 'odl-aaa-moon/aaa-authz/aaa-authz-service')
13 files changed, 1207 insertions, 0 deletions
diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/pom.xml b/odl-aaa-moon/aaa-authz/aaa-authz-service/pom.xml new file mode 100644 index 00000000..a0afef82 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/pom.xml @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + ~ ~ This program and the accompanying materials are made available under + the ~ terms of the Eclipse Public License v1.0 which accompanies this distribution, + ~ and is available at http://www.eclipse.org/legal/epl-v10.html --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.opendaylight.aaa</groupId> + <artifactId>aaa-parent</artifactId> + <version>0.3.1-Beryllium-SR1</version> + <relativePath>../../parent</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>aaa-authz-service</artifactId> + <packaging>bundle</packaging> + + <dependencies> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-util</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-common-util</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-data-api</artifactId> + </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-api</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>config-api</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-config</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.aaa</groupId> + <artifactId>aaa-authz-model</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.aaa</groupId> + <artifactId>aaa-authn-api</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-core-api</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-core-spi</artifactId> + </dependency> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>jaxrs-api</artifactId> + <scope>provided</scope> + </dependency> + + <!-- Test dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <!-- <Bundle-Activator>org.opendaylight.aaa.authz.srv.AuthzProvider</Bundle-Activator> --> + <Export-Package>org.opendaylight.aaa.config.yang.aaa_srv,</Export-Package> + </instructions> + </configuration> + <!-- <configuration> <Export-Package> </Export-Package> </configuration> --> + </plugin> + <plugin> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-maven-plugin</artifactId> + <version>${yangtools.version}</version> + <executions> + <execution> + <id>config</id> + <goals> + <goal>generate-sources</goal> + </goals> + <configuration> + <codeGenerators> + <generator> + <codeGeneratorClass> + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + </codeGeneratorClass> + <outputBaseDir>${jmxGeneratorPath}</outputBaseDir> + <additionalConfiguration> + <namespaceToPackage1> + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + </namespaceToPackage1> + </additionalConfiguration> + </generator> + <generator> + <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass> + <outputBaseDir>${salGeneratorPath}</outputBaseDir> + </generator> + </codeGenerators> + <inspectDependencies>true</inspectDependencies> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>yang-jmx-generator-plugin</artifactId> + <version>${config.version}</version> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal</groupId> + <artifactId>maven-sal-api-gen-plugin</artifactId> + <version>${yangtools.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> + +</project> diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java new file mode 100644 index 00000000..d4ac79af --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzBrokerImpl.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import java.util.Collection; + +import org.opendaylight.aaa.api.AuthenticationService; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Consumer; +import org.opendaylight.controller.sal.core.api.Provider; +import org.osgi.framework.BundleContext; + +/** + * Created by wdec on 26/08/2014. + */ +public class AuthzBrokerImpl implements Broker, AutoCloseable, Provider { + + private Broker broker; + private ProviderSession providerSession; + private AuthenticationService authenticationService; + + public void setBroker(Broker broker) { + this.broker = broker; + } + + @Override + public void close() throws Exception { + + } + + // Implements AuthzBroker handling of registering consumers or providers. + @Override + public ConsumerSession registerConsumer(Consumer consumer) { + + ConsumerSession realSession = broker.registerConsumer(new ConsumerWrapper(consumer)); + AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl(realSession, + this); + consumer.onSessionInitiated(authzConsumerContext); + return authzConsumerContext; + } + + @Override + public ConsumerSession registerConsumer(Consumer consumer, BundleContext bundleContext) { + + ConsumerSession realSession = broker.registerConsumer(new ConsumerWrapper(consumer), + bundleContext); + AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl(realSession, + this); + consumer.onSessionInitiated(authzConsumerContext); + return authzConsumerContext; + } + + @Override + public ProviderSession registerProvider(Provider provider) { + + ProviderSession realSession = broker.registerProvider(new ProviderWrapper(provider)); + AuthzProviderContextImpl authzProviderContext = new AuthzProviderContextImpl(realSession, + this); + provider.onSessionInitiated(authzProviderContext); + return authzProviderContext; + } + + @Override + public ProviderSession registerProvider(Provider provider, BundleContext bundleContext) { + + // Allow the real broker to do its thing, while providing a wrapped + // callback + ProviderSession realSession = broker.registerProvider(new ProviderWrapper(provider), + bundleContext); + + // Create Authz ProviderContext + AuthzProviderContextImpl authzProviderContext = new AuthzProviderContextImpl(realSession, + this); + + // Run onsessionInitiated on injected provider with the AuthZ provider + // context. + provider.onSessionInitiated(authzProviderContext); + return authzProviderContext; + + } + + // Handle the AuthZBroker registration with the real broker + @Override + public void onSessionInitiated(ProviderSession providerSession) { + + // Get now the real DOMDataBroker and register it with the + // AuthzDOMBroker together with the provider session + final DOMDataBroker domDataBroker = providerSession.getService(DOMDataBroker.class); + AuthzDomDataBroker.getInstance().setProviderSession(providerSession); + AuthzDomDataBroker.getInstance().setDomDataBroker(domDataBroker); + AuthzDomDataBroker.getInstance().setAuthService(this.authenticationService); + } + + @Override + public Collection<ProviderFunctionality> getProviderFunctionality() { + return null; + } + + public void setAuthenticationService(AuthenticationService authenticationService) { + this.authenticationService = authenticationService; + } + + // Wrapper for Provider + + public static class ProviderWrapper implements Provider { + private final Provider provider; + + public ProviderWrapper(Provider provider) { + this.provider = provider; + } + + @Override + public void onSessionInitiated(ProviderSession providerSession) { + // Do a Noop when the real broker calls back + } + + @Override + public Collection<ProviderFunctionality> getProviderFunctionality() { + // Allow the RestconfImpl to respond to this + return provider.getProviderFunctionality(); + } + } + + // Wrapper for Consumer + public static class ConsumerWrapper implements Consumer { + + private final Consumer consumer; + + public ConsumerWrapper(Consumer consumer) { + this.consumer = consumer; + } + + @Override + public void onSessionInitiated(ConsumerSession consumerSession) { + // Do a Noop when the real broker calls back + } + + @Override + public Collection<ConsumerFunctionality> getConsumerFunctionality() { + return consumer.getConsumerFunctionality(); + } + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java new file mode 100644 index 00000000..07ba51cd --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.controller.sal.core.spi.ForwardingConsumerSession; + +/** + * Created by wdec on 28/08/2014. + */ +public class AuthzConsumerContextImpl extends ForwardingConsumerSession { + + private final Broker.ConsumerSession realSession; + + public AuthzConsumerContextImpl(Broker.ConsumerSession realSession, AuthzBrokerImpl authzBroker) { + this.realSession = realSession; + } + + @Override + protected ConsumerSession delegate() { + return realSession; + } + + @Override + public <T extends BrokerService> T getService(Class<T> tClass) { + T t; + // Check for class and return Authz broker only for DOMBroker + if (tClass == DOMDataBroker.class) { + t = (T) AuthzDomDataBroker.getInstance(); + } else { + t = realSession.getService(tClass); + } + // AuthzDomDataBroker.getInstance().setDomDataBroker((DOMDataBroker)t); + return t; + } + +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java new file mode 100644 index 00000000..4cc232bc --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDataReadWriteTransaction.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Created by wdec on 26/08/2014. + */ +public class AuthzDataReadWriteTransaction implements DOMDataReadWriteTransaction { + + private final DOMDataReadWriteTransaction domDataReadWriteTransaction; + + public AuthzDataReadWriteTransaction(DOMDataReadWriteTransaction domDataReadWriteTransaction) { + this.domDataReadWriteTransaction = domDataReadWriteTransaction; + } + + @Override + public boolean cancel() { + if (AuthzServiceImpl.isAuthorized(ActionType.Cancel)) { + return domDataReadWriteTransaction.cancel(); + } + return false; + } + + @Override + public void delete(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Delete)) { + domDataReadWriteTransaction.delete(logicalDatastoreType, yangInstanceIdentifier); + } + } + + @Override + public CheckedFuture<Void, TransactionCommitFailedException> submit() { + if (AuthzServiceImpl.isAuthorized(ActionType.Submit)) { + return domDataReadWriteTransaction.submit(); + } + TransactionCommitFailedException e = new TransactionCommitFailedException( + "Unauthorized User"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Deprecated + @Override + public ListenableFuture<RpcResult<TransactionStatus>> commit() { + if (AuthzServiceImpl.isAuthorized(ActionType.Commit)) { + return domDataReadWriteTransaction.commit(); + } + TransactionCommitFailedException e = new TransactionCommitFailedException( + "Unauthorized User"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read( + LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Read)) { + return domDataReadWriteTransaction.read(logicalDatastoreType, yangInstanceIdentifier); + } + ReadFailedException e = new ReadFailedException("Authorization Failed"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public CheckedFuture<Boolean, ReadFailedException> exists( + LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Exists)) { + return domDataReadWriteTransaction.exists(logicalDatastoreType, yangInstanceIdentifier); + } + ReadFailedException e = new ReadFailedException("Authorization Failed"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public void put(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Put)) { + domDataReadWriteTransaction.put(logicalDatastoreType, yangInstanceIdentifier, + normalizedNode); + } + } + + @Override + public void merge(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Merge)) { + domDataReadWriteTransaction.merge(logicalDatastoreType, yangInstanceIdentifier, + normalizedNode); + } + } + + @Override + public Object getIdentifier() { + if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) { + return domDataReadWriteTransaction.getIdentifier(); + } + return null; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java new file mode 100644 index 00000000..911f5a48 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzDomDataBroker.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import java.util.Map; +import org.opendaylight.aaa.api.AuthenticationService; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +/** + * Created by wdec on 26/08/2014. + */ +public class AuthzDomDataBroker implements BrokerService, DOMDataBroker { + + private DOMDataBroker domDataBroker; + private Broker.ProviderSession providerSession; + + private volatile AuthenticationService authService; + + final static AuthzDomDataBroker INSTANCE = new AuthzDomDataBroker(); + + public static AuthzDomDataBroker getInstance() { + return INSTANCE; + } + + public void setDomDataBroker(DOMDataBroker domDataBroker) { + this.domDataBroker = domDataBroker; + } + + public void setProviderSession(Broker.ProviderSession providerSession) { + this.providerSession = providerSession; + } + + public void setAuthService(AuthenticationService authService) { + this.authService = authService; + } + + public AuthenticationService getAuthService() { + return this.authService; + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + // new Authz transaction + inject real DOM Transaction + DOMDataReadOnlyTransaction ro = domDataBroker.newReadOnlyTransaction(); + + // return domDataBroker.newReadOnlyTransaction(); //Return original + return new AuthzReadOnlyTransaction(ro); + } + + @Override + public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() { + return domDataBroker.getSupportedExtensions(); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + // return new Authz transaction + inject real DOM Transaction + DOMDataReadWriteTransaction rw = domDataBroker.newReadWriteTransaction(); + return new AuthzDataReadWriteTransaction(rw); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + DOMDataWriteTransaction wo = domDataBroker.newWriteOnlyTransaction(); + return new AuthzWriteOnlyTransaction(wo); + } + + @Override + public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener( + LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, + DOMDataChangeListener domDataChangeListener, DataChangeScope dataChangeScope) { + return domDataBroker.registerDataChangeListener(logicalDatastoreType, + yangInstanceIdentifier, domDataChangeListener, dataChangeScope); + } + + @Override + public DOMTransactionChain createTransactionChain( + TransactionChainListener transactionChainListener) { + return domDataBroker.createTransactionChain(transactionChainListener); + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java new file mode 100644 index 00000000..dbfea6ed --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzProviderContextImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.controller.sal.core.spi.ForwardingProviderSession; + +/** + * Created by wdec on 28/08/2014. + */ +public class AuthzProviderContextImpl extends ForwardingProviderSession { + + private final Broker.ProviderSession realSession; + + public AuthzProviderContextImpl(Broker.ProviderSession providerSession, + AuthzBrokerImpl authzBroker) { + this.realSession = providerSession; + } + + @Override + protected ProviderSession delegate() { + // TODO Auto-generated method stub + return realSession; + } + + @Override + public <T extends BrokerService> T getService(Class<T> tClass) { + T t; + // Check for class and return Authz broker only for DOMBroker + if (tClass == DOMDataBroker.class) { + t = (T) AuthzDomDataBroker.getInstance(); + } else { + t = realSession.getService(tClass); + } + // AuthzDomDataBroker.getInstance().setDomDataBroker((DOMDataBroker)t); + return t; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java new file mode 100644 index 00000000..c46ffe7c --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzReadOnlyTransaction.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Created by wdec on 28/08/2014. + */ + +public class AuthzReadOnlyTransaction implements DOMDataReadOnlyTransaction { + + private final DOMDataReadOnlyTransaction ro; + + public AuthzReadOnlyTransaction(DOMDataReadOnlyTransaction ro) { + this.ro = ro; + } + + @Override + public void close() { + ro.close(); + } + + @Override + public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read( + LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Read)) { + return ro.read(logicalDatastoreType, yangInstanceIdentifier); + } + ReadFailedException e = new ReadFailedException("Authorization Failed"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public CheckedFuture<Boolean, ReadFailedException> exists( + LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(ActionType.Exists)) { + return ro.exists(logicalDatastoreType, yangInstanceIdentifier); + } + ReadFailedException e = new ReadFailedException("Authorization Failed"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public Object getIdentifier() { + if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) { + return ro.getIdentifier(); + } + return null; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java new file mode 100644 index 00000000..fb344812 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzServiceImpl.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import java.util.List; +import org.opendaylight.aaa.api.Authentication; +import org.opendaylight.aaa.api.AuthenticationService; +import org.opendaylight.controller.config.yang.config.aaa_authz.srv.Policies; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType; +import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.AuthorizationResponseType; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +/** + * @author lmukkama Date: 9/2/14 + */ +public class AuthzServiceImpl { + + private static List<Policies> listPolicies; + + private static final String WILDCARD_TOKEN = "*"; + + public static boolean isAuthorized(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, ActionType actionType) { + + AuthorizationResponseType authorizationResponseType = AuthzServiceImpl.reqAuthorization( + actionType, logicalDatastoreType, yangInstanceIdentifier); + return authorizationResponseType.equals(AuthorizationResponseType.Authorized); + } + + public static boolean isAuthorized(ActionType actionType) { + AuthorizationResponseType authorizationResponseType = AuthzServiceImpl + .reqAuthorization(actionType); + return authorizationResponseType.equals(AuthorizationResponseType.Authorized); + } + + public static void setPolicies(List<Policies> policies) { + + AuthzServiceImpl.listPolicies = policies; + } + + public static AuthorizationResponseType reqAuthorization(ActionType actionType) { + + AuthenticationService authenticationService = AuthzDomDataBroker.getInstance() + .getAuthService(); + if (authenticationService != null && AuthzServiceImpl.listPolicies != null + && AuthzServiceImpl.listPolicies.size() > 0) { + Authentication authentication = authenticationService.get(); + if (authentication != null && authentication.roles() != null + && authentication.roles().size() > 0) { + return checkAuthorization(actionType, authentication); + } + } + return AuthorizationResponseType.NotAuthorized; + } + + public static AuthorizationResponseType reqAuthorization(ActionType actionType, + LogicalDatastoreType logicalDatastoreType, YangInstanceIdentifier yangInstanceIdentifier) { + + AuthenticationService authenticationService = AuthzDomDataBroker.getInstance() + .getAuthService(); + + if (authenticationService != null && AuthzServiceImpl.listPolicies != null + && AuthzServiceImpl.listPolicies.size() > 0) { + // Authentication Service exists. Can do authorization checks + Authentication authentication = authenticationService.get(); + + if (authentication != null && authentication.roles() != null + && authentication.roles().size() > 0) { + // Authentication claim object exists with atleast one role + return checkAuthorization(actionType, authentication, logicalDatastoreType, + yangInstanceIdentifier); + } + } + + return AuthorizationResponseType.Authorized; + } + + private static AuthorizationResponseType checkAuthorization(ActionType actionType, + Authentication authentication, LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier) { + + for (Policies policy : AuthzServiceImpl.listPolicies) { + + // Action type is compared as string, since its type is string in + // the config yang. Comparison is case insensitive + if (authentication.roles().contains(policy.getRole().getValue()) + && (policy.getResource().getValue().equals(WILDCARD_TOKEN) || policy + .getResource().getValue().equals(yangInstanceIdentifier.toString())) + && (policy.getAction().toLowerCase() + .equals(ActionType.Any.name().toLowerCase()) || actionType.name() + .toLowerCase().equals(policy.getAction().toLowerCase()))) { + + return AuthorizationResponseType.Authorized; + } + + } + + // For helium release we unauthorize other requests. + return AuthorizationResponseType.NotAuthorized; + } + + private static AuthorizationResponseType checkAuthorization(ActionType actionType, + Authentication authentication) { + + for (Policies policy : AuthzServiceImpl.listPolicies) { + if (authentication.roles().contains(policy.getRole().getValue()) + && (policy.getAction().equalsIgnoreCase(ActionType.Any.name()) || policy + .getAction().equalsIgnoreCase(actionType.name()))) { + return AuthorizationResponseType.Authorized; + } + } + return AuthorizationResponseType.NotAuthorized; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java new file mode 100644 index 00000000..1123b928 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/aaa/authz/srv/AuthzWriteOnlyTransaction.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yang.gen.v1.urn.aaa.yang.authz.ds.rev140722.ActionType; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Created by wdec on 02/09/2014. + */ +public class AuthzWriteOnlyTransaction implements DOMDataWriteTransaction { + + private final DOMDataWriteTransaction domDataWriteTransaction; + + public AuthzWriteOnlyTransaction(DOMDataWriteTransaction wo) { + this.domDataWriteTransaction = wo; + } + + @Override + public void put(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Put)) { + domDataWriteTransaction.put(logicalDatastoreType, yangInstanceIdentifier, + normalizedNode); + } + } + + @Override + public void merge(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Merge)) { + domDataWriteTransaction.merge(logicalDatastoreType, yangInstanceIdentifier, + normalizedNode); + } + } + + @Override + public boolean cancel() { + if (AuthzServiceImpl.isAuthorized(ActionType.Cancel)) { + return domDataWriteTransaction.cancel(); + } + return false; + } + + @Override + public void delete(LogicalDatastoreType logicalDatastoreType, + YangInstanceIdentifier yangInstanceIdentifier) { + + if (AuthzServiceImpl.isAuthorized(logicalDatastoreType, yangInstanceIdentifier, + ActionType.Delete)) { + domDataWriteTransaction.delete(logicalDatastoreType, yangInstanceIdentifier); + } + } + + @Override + public CheckedFuture<Void, TransactionCommitFailedException> submit() { + if (AuthzServiceImpl.isAuthorized(ActionType.Submit)) { + return domDataWriteTransaction.submit(); + } + TransactionCommitFailedException e = new TransactionCommitFailedException( + "Unauthorized User"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Deprecated + @Override + public ListenableFuture<RpcResult<TransactionStatus>> commit() { + if (AuthzServiceImpl.isAuthorized(ActionType.Commit)) { + return domDataWriteTransaction.commit(); + } + TransactionCommitFailedException e = new TransactionCommitFailedException( + "Unauthorized User"); + return Futures.immediateFailedCheckedFuture(e); + } + + @Override + public Object getIdentifier() { + if (AuthzServiceImpl.isAuthorized(ActionType.GetIdentifier)) { + return domDataWriteTransaction.getIdentifier(); + } + return null; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java new file mode 100644 index 00000000..a590b982 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModule.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.yang.config.aaa_authz.srv; + +import org.opendaylight.aaa.api.AuthenticationService; +import org.opendaylight.aaa.authz.srv.AuthzBrokerImpl; +import org.opendaylight.aaa.authz.srv.AuthzServiceImpl; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AuthzSrvModule extends + org.opendaylight.controller.config.yang.config.aaa_authz.srv.AbstractAuthzSrvModule { + private static final Logger LOG = LoggerFactory.getLogger(AuthzSrvModule.class); + private static boolean simple_config_switch; + private BundleContext bundleContext; + + public AuthzSrvModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public AuthzSrvModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + org.opendaylight.controller.config.yang.config.aaa_authz.srv.AuthzSrvModule oldModule, + java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // checkNotNull(getDomBroker(), domBrokerJmxAttribute); + } + + @Override + public java.lang.AutoCloseable createInstance() { + + // Get new AuthZ Broker + final AuthzBrokerImpl authzBrokerImpl = new AuthzBrokerImpl(); + + // Provide real broker to the new Authz broker + authzBrokerImpl.setBroker(getDomBrokerDependency()); + + // Get AuthN service reference and register it with the authzBroker + ServiceReference<AuthenticationService> authServiceReference = bundleContext + .getServiceReference(AuthenticationService.class); + AuthenticationService as = bundleContext.getService(authServiceReference); + authzBrokerImpl.setAuthenticationService(as); + + // Set the policies list to authz serviceimpl + AuthzServiceImpl.setPolicies(getPolicies()); + + // Register AuthZ broker with the real Broker as a provider; triggers + // "onSessionInitiated" in AuthzBrokerImpl + getDomBrokerDependency().registerProvider(authzBrokerImpl); + // TODO ActionType is of type string, not ENUM due to improper + // serialization of ENUMs by config/netconf subsystem. This needs to be + // fixed as soon as config/netconf fixes the problem. + getAction(); + + LOG.info("AuthZ Service Initialized from Config subsystem"); + return authzBrokerImpl; + + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java new file mode 100644 index 00000000..3ff67f54 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/java/org/opendaylight/controller/config/yang/config/aaa_authz/srv/AuthzSrvModuleFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +/* + * Generated file + * + * Generated from: yang module name: aaa-authz-service-impl yang module local name: aaa-authz-service + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Thu Jul 24 11:19:40 CEST 2014 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.config.aaa_authz.srv; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +public class AuthzSrvModuleFactory extends + org.opendaylight.controller.config.yang.config.aaa_authz.srv.AbstractAuthzSrvModuleFactory { + + @Override + public org.opendaylight.controller.config.spi.Module createModule(String instanceName, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + org.osgi.framework.BundleContext bundleContext) { + + final AuthzSrvModule module = (AuthzSrvModule) super.createModule(instanceName, + dependencyResolver, bundleContext); + + module.setBundleContext(bundleContext); + + return module; + + } + + @Override + public Module createModule(final String instanceName, + final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old, + final BundleContext bundleContext) throws Exception { + final AuthzSrvModule module = (AuthzSrvModule) super.createModule(instanceName, + dependencyResolver, old, bundleContext); + + module.setBundleContext(bundleContext); + + return module; + } +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang new file mode 100644 index 00000000..954d0480 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/main/yang/aaa-authz-service-impl.yang @@ -0,0 +1,115 @@ +module aaa-authz-service-impl { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:aaa-authz:srv"; + prefix "aaa-authz-srv-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import rpc-context { prefix rpcx; revision-date 2013-06-17; } + import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } + import opendaylight-md-sal-dom {prefix dom;} + import authorization-schema { prefix authzs; revision-date 2014-07-22; } + import ietf-inet-types {prefix inet; revision-date 2010-09-24;} + + description + "This module contains the base YANG definitions for + AuthZ implementation."; + + revision "2014-07-01" { + description + "Initial revision."; + } + + + // This is the definition of the service implementation as a module identity. + identity aaa-authz-service { + base config:module-type; + // Specifies the prefix for generated java classes. + config:java-name-prefix AuthzSrv; + config:provided-service dom:dom-broker-osgi-registry; + } + + // Augments the 'configuration' choice node under modules/module. + + augment "/config:modules/config:module/config:configuration" { + case aaa-authz-service { + when "/config:modules/config:module/config:type = 'aaa-authz-service'"; + +//Defines reference to the intended broker under the AuthZ broker + + container dom-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } + } + + container data-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-data-broker; + + } + } + } + +//Simple Authz data leafs: + + leaf authz-role { + type string; + } + leaf service { + type authzs:service-type; + } + + // ENUMs cannot be used right now (config subsystem + netconf cannot properly serialize enums), using strings instead + // In the generated module use Enum.valueOf from that string. + // Expected values are following strnigs: create, read, update, delete, execute, subscribe, any; + leaf action { + type string; + description "String representation of enum authzs:action-type expecting following values create, read, update, delete, execute, subscribe, any"; + //type authzs:action-type; + + } + leaf resource { + type authzs:resource-type; + + } + leaf role { + type authzs:role-type; + } + + + + //TODO: Check why uses below doesn't make the outer list be part of the source name-space in yang code generator. + //uses authzs:authorization-grp; + list policies { + key "service"; + leaf service { + type authzs:service-type; + } + // Grouping uses ENUMs and enums are not correctly serialized in Config + Netconf + // Same as with action one level ip + leaf action { + type string; + description "String representation of enum authzs:action-type expecting following values create, read, update, delete, execute, subscribe, any"; + //type authzs:action-type; + } + leaf resource { + type authzs:resource-type; + + } + leaf role { + type authzs:role-type; + + } + } + + + } + } + +} diff --git a/odl-aaa-moon/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java new file mode 100644 index 00000000..fb033341 --- /dev/null +++ b/odl-aaa-moon/aaa-authz/aaa-authz-service/src/test/java/org/opendaylight/aaa/authz/srv/AuthzConsumerContextImplTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.aaa.authz.srv; + +import org.junit.Assert; +import org.junit.Before; +import org.mockito.Mockito; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Provider; + +public class AuthzConsumerContextImplTest { + + private Broker.ConsumerSession realconsumercontext; + private Provider realprovidercontext; + private AuthzBrokerImpl authzBroker; + private Broker realbroker; + + @Before + public void beforeTest() { + realconsumercontext = Mockito.mock(Broker.ConsumerSession.class); + realprovidercontext = Mockito.mock(Provider.class); + realbroker = Mockito.mock(Broker.class); + realbroker.registerProvider(realprovidercontext); + authzBroker = Mockito.mock(AuthzBrokerImpl.class); + } + + @org.junit.Test + public void testGetService() throws Exception { + AuthzConsumerContextImpl authzConsumerContext = new AuthzConsumerContextImpl( + realconsumercontext, authzBroker); + + Assert.assertEquals("Expected Authz session context", + authzConsumerContext.getService(DOMDataBroker.class).getClass(), + AuthzDomDataBroker.class); + // Assert.assertEquals("Expected Authz session context", + // authzConsumerContext.getService(SchemaService.class).getClass(), + // SchemaService.class); + } +}
\ No newline at end of file |